1 /* Copyright (c) 2000, 2014, Oracle and/or its affiliates
2    Copyright (c) 2009, 2017, MariaDB Corporation
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation.
7 
8    There are special exceptions to the terms and conditions of the GPL as it
9    is applied to this software. View the full text of the exception in file
10    EXCEPTIONS-CLIENT in the directory of this software distribution.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */
20 
21 #include <my_global.h>
22 #include <my_sys.h>
23 #include <my_time.h>
24 #include <mysys_err.h>
25 #include <m_string.h>
26 #include <m_ctype.h>
CreateCXXTemporaryObject(const MaterializeTemporaryExpr * ME,ExplodedNode * Pred,ExplodedNodeSet & Dst)27 #include "mysql.h"
28 #include "mysql_version.h"
29 #include "mysqld_error.h"
30 #include "errmsg.h"
31 #include <violite.h>
32 #include <sys/stat.h>
33 #include <signal.h>
34 #include <time.h>
35 #ifdef	 HAVE_PWD_H
36 #include <pwd.h>
37 #endif
38 #if !defined(__WIN__)
39 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42 #include <netdb.h>
43 #ifdef HAVE_SELECT_H
44 #include <select.h>
45 #endif
46 #ifdef HAVE_SYS_SELECT_H
47 #include <sys/select.h>
48 #endif
49 #endif /* !defined(__WIN__) */
50 #if defined(HAVE_POLL_H)
51 #include <poll.h>
52 #elif defined(HAVE_SYS_POLL_H)
53 #include <sys/poll.h>
54 #endif /* defined(HAVE_POLL_H) */
55 #ifdef HAVE_SYS_UN_H
56 #include <sys/un.h>
57 #endif
58 #if !defined(__WIN__)
59 #include <my_pthread.h>				/* because of signal()	*/
60 #endif
61 #ifndef INADDR_NONE
62 #define INADDR_NONE	-1
63 #endif
64 
65 #include <sql_common.h>
66 #include "client_settings.h"
67 
68 #undef net_buffer_length
69 #undef max_allowed_packet
70 
71 ulong 		net_buffer_length=8192;
72 ulong		max_allowed_packet= 1024L*1024L*1024L;
73 
74 
75 #ifdef EMBEDDED_LIBRARY
76 #undef net_flush
77 my_bool	net_flush(NET *net);
78 #endif
79 
80 #if defined(__WIN__)
81 /* socket_errno is defined in my_global.h for all platforms */
82 #define perror(A)
83 #else
84 #include <errno.h>
85 #define SOCKET_ERROR -1
86 #endif /* __WIN__ */
87 
88 /*
89   If allowed through some configuration, then this needs to
90   be changed
91 */
92 #define MAX_LONG_DATA_LENGTH 8192
93 #define unsigned_field(A) ((A)->flags & UNSIGNED_FLAG)
94 
95 static void append_wild(char *to,char *end,const char *wild);
96 sig_handler my_pipe_sig_handler(int sig);
97 
98 static my_bool mysql_client_init= 0;
makeZeroElementRegion(ProgramStateRef State,SVal LValue,QualType & Ty,bool & IsArray)99 static my_bool org_my_init_done= 0;
100 
101 typedef struct st_mysql_stmt_extension
102 {
103   MEM_ROOT fields_mem_root;
104 } MYSQL_STMT_EXT;
105 
106 
107 /*
108   Initialize the MySQL client library
109 
110   SYNOPSIS
111     mysql_server_init()
112 
prepareForObjectConstruction(const Expr * E,ProgramStateRef State,const LocationContext * LCtx,const ConstructionContext * CC,EvalCallOptions & CallOpts)113   NOTES
114     Should be called before doing any other calls to the MySQL
115     client library to initialize thread specific variables etc.
116     It's called by mysql_init() to ensure that things will work for
117     old not threaded applications that doesn't call mysql_server_init()
118     directly.
119 
120   RETURN
121     0  ok
122     1  could not initialize environment (out of memory or thread keys)
123 */
124 
125 int STDCALL mysql_server_init(int argc __attribute__((unused)),
126                               char **argv __attribute__((unused)),
127                               char **groups __attribute__((unused)))
128 {
129   int result= 0;
130   if (!mysql_client_init)
131   {
132     mysql_client_init=1;
133     org_my_init_done=my_init_done;
134     if (my_init())				/* Will init threads */
135       return 1;
136     init_client_errs();
137     if (mysql_client_plugin_init())
138       return 1;
139     if (!mysql_port)
140     {
141       char *env;
142       struct servent *serv_ptr __attribute__((unused));
143 
144       mysql_port = MYSQL_PORT;
145 
146       /*
147         if builder specifically requested a default port, use that
148         (even if it coincides with our factory default).
149         only if they didn't do we check /etc/services (and, failing
150         on that, fall back to the factory default of 3306).
151         either default can be overridden by the environment variable
152         MYSQL_TCP_PORT, which in turn can be overridden with command
153         line options.
154       */
155 
156 #if MYSQL_PORT_DEFAULT == 0
157 # if !__has_feature(memory_sanitizer) // Work around MSAN deficiency
158       if ((serv_ptr= getservbyname("mysql", "tcp")))
159         mysql_port= (uint) ntohs((ushort) serv_ptr->s_port);
160 # endif
161 #endif
162       if ((env= getenv("MYSQL_TCP_PORT")))
163         mysql_port=(uint) atoi(env);
164     }
165 
166     if (!mysql_unix_port)
167     {
168       char *env;
169 #ifdef __WIN__
170       mysql_unix_port = (char*) MYSQL_NAMEDPIPE;
171 #else
172       mysql_unix_port = (char*) MYSQL_UNIX_ADDR;
173 #endif
174       if ((env = getenv("MYSQL_UNIX_PORT")))
175 	mysql_unix_port = env;
176     }
177     mysql_debug(NullS);
178 #if defined(SIGPIPE) && !defined(__WIN__)
179     (void) signal(SIGPIPE, SIG_IGN);
180 #endif
181 #ifdef EMBEDDED_LIBRARY
182     if (argc > -1)
183        result= init_embedded_server(argc, argv, groups);
184 #endif
185   }
186   else
187     result= (int)my_thread_init();         /* Init if new thread */
188   return result;
189 }
190 
191 
192 /*
193   Free all memory and resources used by the client library
194 
195   NOTES
196     When calling this there should not be any other threads using
197     the library.
198 
199     To make things simpler when used with windows dll's (which calls this
200     function automatically), it's safe to call this function multiple times.
201 */
202 
203 
204 void STDCALL mysql_server_end()
205 {
206   if (!mysql_client_init)
207     return;
208 
209   mysql_client_plugin_deinit();
210 
211   finish_client_errs();
212   if (mariadb_deinitialize_ssl)
213     vio_end();
214 #ifdef EMBEDDED_LIBRARY
215   end_embedded_server();
216 #endif
217 
218   /* If library called my_init(), free memory allocated by it */
219   if (!org_my_init_done)
220   {
221     my_end(0);
222   }
223 #ifdef NOT_NEEDED
224   /*
225     The following is not needed as if the program explicitly called
226     my_init() then we can assume it will also call my_end().
227     The reason to not also do it here is in that case we can't get
228     statistics from my_end() to debug log.
229   */
230   else
231   {
232     free_charsets();
233     mysql_thread_end();
234   }
235 #endif
236 
237   mysql_client_init= org_my_init_done= 0;
238 }
239 
240 static MYSQL_PARAMETERS mysql_internal_parameters=
241 {&max_allowed_packet, &net_buffer_length, 0};
242 
243 MYSQL_PARAMETERS *STDCALL mysql_get_parameters(void)
244 {
245   return &mysql_internal_parameters;
246 }
247 
248 my_bool STDCALL mysql_thread_init()
249 {
250   return my_thread_init();
251 }
252 
253 void STDCALL mysql_thread_end()
254 {
255   my_thread_end();
256 }
257 
258 
259 /*
260   Expand wildcard to a sql string
261 */
262 
263 static void
264 append_wild(char *to, char *end, const char *wild)
265 {
266   end-=5;					/* Some extra */
267   if (wild && wild[0])
268   {
269     to=strmov(to," like '");
270     while (*wild && to < end)
271     {
272       if (*wild == '\\' || *wild == '\'')
273 	*to++='\\';
274       *to++= *wild++;
275     }
276     if (*wild)					/* Too small buffer */
277       *to++='%';				/* Nicer this way */
278     to[0]='\'';
279     to[1]=0;
280   }
281 }
282 
283 
284 /**************************************************************************
285   Init debugging if MYSQL_DEBUG environment variable is found
286 **************************************************************************/
287 
288 void STDCALL
289 mysql_debug(const char *debug __attribute__((unused)))
290 {
291 #ifndef DBUG_OFF
292   char	*env;
293   if (debug)
294   {
295     DBUG_PUSH(debug);
296   }
297   else if ((env = getenv("MYSQL_DEBUG")))
298   {
299     DBUG_PUSH(env);
300 #if !defined(_WINVER) && !defined(WINVER)
301     puts("\n-------------------------------------------------------");
302     puts("MYSQL_DEBUG found. libmysql started with the following:");
303     puts(env);
304     puts("-------------------------------------------------------\n");
305 #else
306     {
307       char buff[80];
308       buff[sizeof(buff)-1]= 0;
309       strxnmov(buff,sizeof(buff)-1,"libmysql: ", env, NullS);
310       MessageBox((HWND) 0,"Debugging variable MYSQL_DEBUG used",buff,MB_OK);
311     }
312 #endif
313   }
314 #endif
315 }
316 
317 
318 /**************************************************************************
319   Ignore SIGPIPE handler
__anonbd886f050102(CallEventRef<> Caller) 320    ARGSUSED
321 **************************************************************************/
322 
323 sig_handler
324 my_pipe_sig_handler(int sig __attribute__((unused)))
325 {
326   DBUG_PRINT("info",("Hit by signal %d",sig));
327 #ifdef SIGNAL_HANDLER_RESET_ON_DELIVERY
328   (void) signal(SIGPIPE, my_pipe_sig_handler);
329 #endif
330 }
331 
332 
333 /**************************************************************************
334   Connect to sql server
335   If host == 0 then use localhost
336 **************************************************************************/
337 
338 #ifdef USE_OLD_FUNCTIONS
339 MYSQL * STDCALL
340 mysql_connect(MYSQL *mysql,const char *host,
341 	      const char *user, const char *passwd)
342 {
343   MYSQL *res;
344   mysql=mysql_init(mysql);			/* Make it thread safe */
345   {
346     DBUG_ENTER("mysql_connect");
347     if (!(res=mysql_real_connect(mysql,host,user,passwd,NullS,0,NullS,0)))
348     {
349       if (mysql->free_me)
350 	my_free(mysql);
351     }
352     mysql->reconnect= 1;
353     DBUG_RETURN(res);
354   }
355 }
356 #endif
357 
358 
359 /**************************************************************************
360   Change user and database
361 **************************************************************************/
362 
363 my_bool	STDCALL mysql_change_user(MYSQL *mysql, const char *user,
364 				  const char *passwd, const char *db)
365 {
366   int rc;
367   CHARSET_INFO *saved_cs= mysql->charset;
368   char *saved_user= mysql->user;
369   char *saved_passwd= mysql->passwd;
370   char *saved_db= mysql->db;
371 
372   DBUG_ENTER("mysql_change_user");
373 
374   /* Get the connection-default character set. */
375 
376   if (mysql_init_character_set(mysql))
377   {
378     mysql->charset= saved_cs;
379     DBUG_RETURN(TRUE);
380   }
381 
382   /* Use an empty string instead of NULL. */
383 
384   mysql->user= (char*)(user ? user : "");
385   mysql->passwd= (char*)(passwd ? passwd : "");
386   mysql->db= 0;
387 
388   rc= run_plugin_auth(mysql, 0, 0, 0, db);
VisitCXXConstructExpr(const CXXConstructExpr * CE,ExplodedNode * Pred,ExplodedNodeSet & destNodes)389 
390   /*
391     The server will close all statements no matter was the attempt
392     to change user successful or not.
393   */
394   mysql_detach_stmt_list(&mysql->stmts, "mysql_change_user");
395   if (rc == 0)
396   {
397     /* Free old connect information */
398     my_free(saved_user);
399     my_free(saved_passwd);
400     my_free(saved_db);
401 
402     /* alloc new connect information */
403     mysql->user= my_strdup(mysql->user, MYF(MY_WME));
404     mysql->passwd= my_strdup(mysql->passwd, MYF(MY_WME));
405     mysql->db= db ? my_strdup(db, MYF(MY_WME)) : 0;
406   }
407   else
408   {
409     mysql->charset= saved_cs;
410     mysql->user= saved_user;
411     mysql->passwd= saved_passwd;
412     mysql->db= saved_db;
413   }
414 
415   DBUG_RETURN(rc);
416 }
417 
418 #if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
419 struct passwd *getpwuid(uid_t);
420 char* getlogin(void);
421 #endif
422 
423 #if !defined(__WIN__)
424 
425 void read_user_name(char *name)
426 {
427   DBUG_ENTER("read_user_name");
428   if (geteuid() == 0)
429     (void) strmov(name,"root");		/* allow use of surun */
430   else
431   {
432 #ifdef HAVE_GETPWUID
433     struct passwd *skr;
434     const char *str;
435     if ((str=getlogin()) == NULL)
436     {
437       if ((skr=getpwuid(geteuid())) != NULL)
438 	str=skr->pw_name;
439       else if (!(str=getenv("USER")) && !(str=getenv("LOGNAME")) &&
440 	       !(str=getenv("LOGIN")))
441 	str="UNKNOWN_USER";
442     }
443     (void) strmake(name,str,USERNAME_LENGTH);
444 #elif HAVE_CUSERID
445     (void) cuserid(name);
446 #else
447     strmov(name,"UNKNOWN_USER");
448 #endif
449   }
450   DBUG_VOID_RETURN;
451 }
452 
453 #else /* If Windows */
454 
455 void read_user_name(char *name)
456 {
457   DWORD len= USERNAME_LENGTH;
458   if (!GetUserName(name, &len))
459     strmov(name,"UNKNOWN_USER");
460 }
461 
462 #endif
463 
464 my_bool handle_local_infile(MYSQL *mysql, const char *net_filename)
465 {
466   my_bool result= 1;
467   uint packet_length=MY_ALIGN(mysql->net.max_packet-16,IO_SIZE);
468   NET *net= &mysql->net;
469   int readcount;
470   void *li_ptr;          /* pass state to local_infile functions */
471   char *buf;		/* buffer to be filled by local_infile_read */
472   struct st_mysql_options *options= &mysql->options;
473   DBUG_ENTER("handle_local_infile");
474 
475   /* check that we've got valid callback functions */
476   if (!(options->local_infile_init &&
477 	options->local_infile_read &&
478 	options->local_infile_end &&
479 	options->local_infile_error))
480   {
481     /* if any of the functions is invalid, set the default */
482     mysql_set_local_infile_default(mysql);
483   }
484 
485   /* copy filename into local memory and allocate read buffer */
486   if (!(buf=my_malloc(packet_length, MYF(0))))
487   {
488     set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
489     DBUG_RETURN(1);
490   }
491 
492   /* initialize local infile (open file, usually) */
493   if ((*options->local_infile_init)(&li_ptr, net_filename,
494     options->local_infile_userdata))
495   {
496     (void) my_net_write(net,(const uchar*) "",0); /* Server needs one packet */
497     net_flush(net);
498     strmov(net->sqlstate, unknown_sqlstate);
499     net->last_errno=
500       (*options->local_infile_error)(li_ptr,
501                                      net->last_error,
502                                      sizeof(net->last_error)-1);
503     goto err;
504   }
505 
506   /* read blocks of data from local infile callback */
507   while ((readcount =
508 	  (*options->local_infile_read)(li_ptr, buf,
509 					packet_length)) > 0)
510   {
511     if (my_net_write(net, (uchar*) buf, readcount))
512     {
513       DBUG_PRINT("error",
514 		 ("Lost connection to MySQL server during LOAD DATA of local file"));
515       set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate);
516       goto err;
517     }
518   }
519 
520   /* Send empty packet to mark end of file */
521   if (my_net_write(net, (const uchar*) "", 0) || net_flush(net))
522   {
523     set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate);
524     goto err;
525   }
526 
527   if (readcount < 0)
528   {
529     net->last_errno=
530       (*options->local_infile_error)(li_ptr,
531                                      net->last_error,
532                                      sizeof(net->last_error)-1);
533     goto err;
534   }
535 
536   result=0;					/* Ok */
537 
538 err:
539   /* free up memory allocated with _init, usually */
540   (*options->local_infile_end)(li_ptr);
541   my_free(buf);
542   DBUG_RETURN(result);
543 }
544 
545 
546 /****************************************************************************
547   Default handlers for LOAD LOCAL INFILE
548 ****************************************************************************/
549 
550 typedef struct st_default_local_infile
551 {
552   int fd;
553   int error_num;
554   const char *filename;
555   char error_msg[LOCAL_INFILE_ERROR_LEN];
556 } default_local_infile_data;
557 
558 
559 /*
560   Open file for LOAD LOCAL INFILE
561 
562   SYNOPSIS
563     default_local_infile_init()
564     ptr			Store pointer to internal data here
565     filename		File name to open. This may be in unix format !
566 
567 
568   NOTES
569     Even if this function returns an error, the load data interface
570     guarantees that default_local_infile_end() is called.
571 
572   RETURN
573     0	ok
574     1	error
575 */
576 
577 static int default_local_infile_init(void **ptr, const char *filename,
578              void *userdata __attribute__ ((unused)))
579 {
580   default_local_infile_data *data;
581   char tmp_name[FN_REFLEN];
582 
583   if (!(*ptr= data= ((default_local_infile_data *)
584 		     my_malloc(sizeof(default_local_infile_data),  MYF(0)))))
585     return 1; /* out of memory */
586 
587   data->error_msg[0]= 0;
588   data->error_num=    0;
589   data->filename= filename;
590 
591   fn_format(tmp_name, filename, "", "", MY_UNPACK_FILENAME);
592   if ((data->fd = my_open(tmp_name, O_RDONLY, MYF(0))) < 0)
593   {
594     data->error_num= my_errno;
595     my_snprintf(data->error_msg, sizeof(data->error_msg)-1,
596                 EE(EE_FILENOTFOUND), tmp_name, data->error_num);
597     return 1;
598   }
599   return 0; /* ok */
VisitCXXDestructor(QualType ObjectType,const MemRegion * Dest,const Stmt * S,bool IsBaseDtor,ExplodedNode * Pred,ExplodedNodeSet & Dst,const EvalCallOptions & CallOpts)600 }
601 
602 
603 /*
604   Read data for LOAD LOCAL INFILE
605 
606   SYNOPSIS
607     default_local_infile_read()
608     ptr			Points to handle allocated by _init
609     buf			Read data here
610     buf_len		Amount of data to read
611 
612   RETURN
613     > 0		number of bytes read
614     == 0	End of data
615     < 0		Error
616 */
617 
618 static int default_local_infile_read(void *ptr, char *buf, uint buf_len)
619 {
620   int count;
621   default_local_infile_data*data = (default_local_infile_data *) ptr;
622 
623   if ((count= (int) my_read(data->fd, (uchar *) buf, buf_len, MYF(0))) < 0)
624   {
625     data->error_num= EE_READ; /* the errmsg for not entire file read */
626     my_snprintf(data->error_msg, sizeof(data->error_msg)-1,
627 		EE(EE_READ),
628 		data->filename, my_errno);
629   }
630   return count;
631 }
632 
633 
634 /*
635   Read data for LOAD LOCAL INFILE
636 
VisitCXXNewAllocatorCall(const CXXNewExpr * CNE,ExplodedNode * Pred,ExplodedNodeSet & Dst)637   SYNOPSIS
638     default_local_infile_end()
639     ptr			Points to handle allocated by _init
640 			May be NULL if _init failed!
641 
642   RETURN
643 */
644 
645 static void default_local_infile_end(void *ptr)
646 {
647   default_local_infile_data *data= (default_local_infile_data *) ptr;
648   if (data)					/* If not error on open */
649   {
650     if (data->fd >= 0)
651       my_close(data->fd, MYF(MY_WME));
652     my_free(ptr);
653   }
654 }
655 
656 
657 /*
658   Return error from LOAD LOCAL INFILE
659 
660   SYNOPSIS
661     default_local_infile_end()
662     ptr			Points to handle allocated by _init
663 			May be NULL if _init failed!
664     error_msg		Store error text here
665     error_msg_len	Max length of error_msg
666 
667   RETURN
668     error message number
669 */
670 
671 static int
672 default_local_infile_error(void *ptr, char *error_msg, uint error_msg_len)
673 {
674   default_local_infile_data *data = (default_local_infile_data *) ptr;
675   if (data)					/* If not error on open */
676   {
677     strmake(error_msg, data->error_msg, error_msg_len);
678     return data->error_num;
679   }
680   /* This can only happen if we got error on malloc of handle */
681   strmov(error_msg, ER(CR_OUT_OF_MEMORY));
682   return CR_OUT_OF_MEMORY;
683 }
684 
685 
686 void
687 mysql_set_local_infile_handler(MYSQL *mysql,
688                                int (*local_infile_init)(void **, const char *,
689                                void *),
690                                int (*local_infile_read)(void *, char *, uint),
691                                void (*local_infile_end)(void *),
692                                int (*local_infile_error)(void *, char *, uint),
693                                void *userdata)
694 {
695   mysql->options.local_infile_init=  local_infile_init;
696   mysql->options.local_infile_read=  local_infile_read;
697   mysql->options.local_infile_end=   local_infile_end;
698   mysql->options.local_infile_error= local_infile_error;
699   mysql->options.local_infile_userdata = userdata;
700 }
701 
702 
703 void mysql_set_local_infile_default(MYSQL *mysql)
704 {
705   mysql->options.local_infile_init=  default_local_infile_init;
VisitCXXNewExpr(const CXXNewExpr * CNE,ExplodedNode * Pred,ExplodedNodeSet & Dst)706   mysql->options.local_infile_read=  default_local_infile_read;
707   mysql->options.local_infile_end=   default_local_infile_end;
708   mysql->options.local_infile_error= default_local_infile_error;
709 }
710 
711 
712 /**************************************************************************
713   Do a query. If query returned rows, free old rows.
714   Read data by mysql_store_result or by repeat call of mysql_fetch_row
715 **************************************************************************/
716 
717 int STDCALL
718 mysql_query(MYSQL *mysql, const char *query)
719 {
720   return mysql_real_query(mysql,query, (uint) strlen(query));
721 }
722 
723 
724 /**************************************************************************
725   Return next field of the query results
726 **************************************************************************/
727 
728 MYSQL_FIELD * STDCALL
729 mysql_fetch_field(MYSQL_RES *result)
730 {
731   if (result->current_field >= result->field_count)
732     return(NULL);
733   return &result->fields[result->current_field++];
734 }
735 
736 
737 /**************************************************************************
738   Move to a specific row and column
739 **************************************************************************/
740 
741 void STDCALL
742 mysql_data_seek(MYSQL_RES *result, my_ulonglong row)
743 {
744   MYSQL_ROWS	*tmp=0;
745   DBUG_PRINT("info",("mysql_data_seek(%ld)",(long) row));
746   if (result->data)
747     for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ;
748   result->current_row=0;
749   result->data_cursor = tmp;
750 }
751 
752 
753 /*************************************************************************
754   put the row or field cursor one a position one got from mysql_row_tell()
755   This doesn't restore any data. The next mysql_fetch_row or
756   mysql_fetch_field will return the next row or field after the last used
757 *************************************************************************/
758 
759 MYSQL_ROW_OFFSET STDCALL
760 mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET row)
761 {
762   MYSQL_ROW_OFFSET return_value=result->data_cursor;
763   result->current_row= 0;
764   result->data_cursor= row;
765   return return_value;
766 }
767 
768 
769 MYSQL_FIELD_OFFSET STDCALL
770 mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET field_offset)
771 {
772   MYSQL_FIELD_OFFSET return_value=result->current_field;
773   result->current_field=field_offset;
774   return return_value;
775 }
776 
777 
778 /*****************************************************************************
779   List all databases
780 *****************************************************************************/
781 
782 MYSQL_RES * STDCALL
783 mysql_list_dbs(MYSQL *mysql, const char *wild)
784 {
785   char buff[255];
786   DBUG_ENTER("mysql_list_dbs");
787 
788   append_wild(strmov(buff,"show databases"),buff+sizeof(buff),wild);
789   if (mysql_query(mysql,buff))
790     DBUG_RETURN(0);
791   DBUG_RETURN (mysql_store_result(mysql));
792 }
793 
794 
795 /*****************************************************************************
796   List all tables in a database
797   If wild is given then only the tables matching wild is returned
798 *****************************************************************************/
799 
800 MYSQL_RES * STDCALL
801 mysql_list_tables(MYSQL *mysql, const char *wild)
802 {
803   char buff[255];
804   DBUG_ENTER("mysql_list_tables");
805 
806   append_wild(strmov(buff,"show tables"),buff+sizeof(buff),wild);
807   if (mysql_query(mysql,buff))
808     DBUG_RETURN(0);
809   DBUG_RETURN (mysql_store_result(mysql));
810 }
811 
812 
813 MYSQL_FIELD *cli_list_fields(MYSQL *mysql)
814 {
815   MYSQL_DATA *query;
VisitCXXDeleteExpr(const CXXDeleteExpr * CDE,ExplodedNode * Pred,ExplodedNodeSet & Dst)816   if (!(query= cli_read_rows(mysql,(MYSQL_FIELD*) 0,
817 			     protocol_41(mysql) ? 8 : 6)))
818     return NULL;
819 
820   mysql->field_count= (uint) query->rows;
821   return unpack_fields(mysql, query,&mysql->field_alloc,
822 		       mysql->field_count, 1, mysql->server_capabilities);
VisitCXXCatchStmt(const CXXCatchStmt * CS,ExplodedNode * Pred,ExplodedNodeSet & Dst)823 }
824 
825 
826 /**************************************************************************
827   List all fields in a table
828   If wild is given then only the fields matching wild is returned
829   Instead of this use query:
830   show fields in 'table' like "wild"
831 **************************************************************************/
832 
833 MYSQL_RES * STDCALL
834 mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)
835 {
836   MYSQL_RES   *result;
837   MYSQL_FIELD *fields;
838   char	     buff[258],*end;
839   DBUG_ENTER("mysql_list_fields");
840   DBUG_PRINT("enter",("table: '%s'  wild: '%s'",table,wild ? wild : ""));
841 
842   end=strmake(strmake(buff, table,128)+1,wild ? wild : "",128);
843   free_old_query(mysql);
844   if (simple_command(mysql, COM_FIELD_LIST, (uchar*) buff,
845                      (ulong) (end-buff), 1) ||
846       !(fields= (*mysql->methods->list_fields)(mysql)))
847     DBUG_RETURN(NULL);
848 
849   if (!(result = (MYSQL_RES *) my_malloc(sizeof(MYSQL_RES),
850 					 MYF(MY_WME | MY_ZEROFILL))))
851     DBUG_RETURN(NULL);
852 
853   result->methods= mysql->methods;
854   result->field_alloc=mysql->field_alloc;
855   mysql->fields=0;
856   result->field_count = mysql->field_count;
857   result->fields= fields;
858   result->eof=1;
859   DBUG_RETURN(result);
860 }
861 
862 /* List all running processes (threads) in server */
863 
864 MYSQL_RES * STDCALL
865 mysql_list_processes(MYSQL *mysql)
866 {
867   MYSQL_DATA *UNINIT_VAR(fields);
868   uint field_count;
869   uchar *pos;
870   DBUG_ENTER("mysql_list_processes");
871 
872   if (simple_command(mysql,COM_PROCESS_INFO,0,0,0))
873     DBUG_RETURN(0);
874   free_old_query(mysql);
875   pos=(uchar*) mysql->net.read_pos;
876   field_count=(uint) net_field_length(&pos);
877   if (!(fields = (*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*) 0,
878 					      protocol_41(mysql) ? 7 : 5)))
879     DBUG_RETURN(NULL);
880   if (!(mysql->fields=unpack_fields(mysql, fields,&mysql->field_alloc,field_count,0,
881 				    mysql->server_capabilities)))
882     DBUG_RETURN(0);
883   mysql->status=MYSQL_STATUS_GET_RESULT;
884   mysql->field_count=field_count;
885   DBUG_RETURN(mysql_store_result(mysql));
886 }
887 
888 
889 #ifdef USE_OLD_FUNCTIONS
890 int  STDCALL
891 mysql_create_db(MYSQL *mysql, const char *db)
892 {
893   DBUG_ENTER("mysql_createdb");
894   DBUG_PRINT("enter",("db: %s",db));
895   DBUG_RETURN(simple_command(mysql,COM_CREATE_DB,db, (ulong) strlen(db),0));
896 }
897 
898 
899 int  STDCALL
900 mysql_drop_db(MYSQL *mysql, const char *db)
901 {
902   DBUG_ENTER("mysql_drop_db");
903   DBUG_PRINT("enter",("db: %s",db));
904   DBUG_RETURN(simple_command(mysql,COM_DROP_DB,db,(ulong) strlen(db),0));
905 }
906 #endif
907 
908 
909 int STDCALL
910 mysql_shutdown(MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level)
911 {
912   uchar level[1];
913   DBUG_ENTER("mysql_shutdown");
914   level[0]= (uchar) shutdown_level;
915   DBUG_RETURN(simple_command(mysql, COM_SHUTDOWN, level, 1, 0));
916 }
917 
918 
919 int STDCALL
920 mysql_refresh(MYSQL *mysql,uint options)
921 {
922   uchar bits[1];
923   DBUG_ENTER("mysql_refresh");
924   bits[0]= (uchar) options;
925   DBUG_RETURN(simple_command(mysql, COM_REFRESH, bits, 1, 0));
926 }
927 
928 
929 int STDCALL
930 mysql_kill(MYSQL *mysql,ulong pid)
931 {
932   uchar buff[4];
933   DBUG_ENTER("mysql_kill");
934   int4store(buff,pid);
935   DBUG_RETURN(simple_command(mysql,COM_PROCESS_KILL,buff,sizeof(buff),0));
936 }
937 
938 
939 int STDCALL
940 mysql_set_server_option(MYSQL *mysql, enum enum_mysql_set_option option)
941 {
942   uchar buff[2];
943   DBUG_ENTER("mysql_set_server_option");
944   int2store(buff, (uint) option);
945   DBUG_RETURN(simple_command(mysql, COM_SET_OPTION, buff, sizeof(buff), 0));
946 }
947 
948 
949 int STDCALL
950 mysql_dump_debug_info(MYSQL *mysql)
951 {
952   DBUG_ENTER("mysql_dump_debug_info");
953   DBUG_RETURN(simple_command(mysql,COM_DEBUG,0,0,0));
954 }
955 
956 
957 const char *cli_read_statistics(MYSQL *mysql)
958 {
959   mysql->net.read_pos[mysql->packet_length]=0;	/* End of stat string */
960   if (!mysql->net.read_pos[0])
961   {
962     set_mysql_error(mysql, CR_WRONG_HOST_INFO, unknown_sqlstate);
963     return mysql->net.last_error;
964   }
965   return (char*) mysql->net.read_pos;
966 }
967 
968 
969 const char * STDCALL
970 mysql_stat(MYSQL *mysql)
971 {
972   DBUG_ENTER("mysql_stat");
973   if (simple_command(mysql,COM_STATISTICS,0,0,0))
974     DBUG_RETURN(mysql->net.last_error);
975   DBUG_RETURN((*mysql->methods->read_statistics)(mysql));
976 }
977 
978 
979 int STDCALL
980 mysql_ping(MYSQL *mysql)
981 {
982   int res;
983   DBUG_ENTER("mysql_ping");
984   res= simple_command(mysql,COM_PING,0,0,0);
985   if (res == CR_SERVER_LOST && mysql->reconnect)
986     res= simple_command(mysql,COM_PING,0,0,0);
987   DBUG_RETURN(res);
988 }
989 
990 
991 const char * STDCALL
992 mysql_get_server_info(MYSQL *mysql)
993 {
994   return((char*) mysql->server_version);
995 }
996 
997 
998 my_bool STDCALL mariadb_connection(MYSQL *mysql)
999 {
1000   return (strstr(mysql->server_version, "MariaDB") ||
1001           strstr(mysql->server_version, "-maria-"));
1002 }
1003 
1004 const char * STDCALL
1005 mysql_get_server_name(MYSQL *mysql)
1006 {
1007   return mariadb_connection(mysql) ? "MariaDB" : "MySQL";
1008 }
1009 
1010 
1011 const char * STDCALL
1012 mysql_get_host_info(MYSQL *mysql)
1013 {
1014   return(mysql->host_info);
1015 }
1016 
1017 
1018 uint STDCALL
1019 mysql_get_proto_info(MYSQL *mysql)
1020 {
1021   return (mysql->protocol_version);
1022 }
1023 
1024 const char * STDCALL
1025 mysql_get_client_info(void)
1026 {
1027   return (char*) MYSQL_SERVER_VERSION;
1028 }
1029 
1030 ulong STDCALL mysql_get_client_version(void)
1031 {
1032   return MYSQL_VERSION_ID;
1033 }
1034 
1035 my_bool STDCALL mysql_eof(MYSQL_RES *res)
1036 {
1037   return res->eof;
1038 }
1039 
1040 MYSQL_FIELD * STDCALL mysql_fetch_field_direct(MYSQL_RES *res,uint fieldnr)
1041 {
1042   return &(res)->fields[fieldnr];
1043 }
1044 
1045 MYSQL_FIELD * STDCALL mysql_fetch_fields(MYSQL_RES *res)
1046 {
1047   return (res)->fields;
1048 }
1049 
1050 MYSQL_ROW_OFFSET STDCALL mysql_row_tell(MYSQL_RES *res)
1051 {
1052   return res->data_cursor;
1053 }
1054 
1055 MYSQL_FIELD_OFFSET STDCALL mysql_field_tell(MYSQL_RES *res)
1056 {
1057   return (res)->current_field;
1058 }
1059 
1060 /* MYSQL */
1061 
1062 unsigned int STDCALL mysql_field_count(MYSQL *mysql)
1063 {
1064   return mysql->field_count;
1065 }
1066 
1067 my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql)
1068 {
1069   return mysql->affected_rows;
1070 }
1071 
1072 my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql)
1073 {
1074   return mysql->insert_id;
1075 }
1076 
1077 const char *STDCALL mysql_sqlstate(MYSQL *mysql)
1078 {
1079   return mysql ? mysql->net.sqlstate : cant_connect_sqlstate;
1080 }
1081 
1082 uint STDCALL mysql_warning_count(MYSQL *mysql)
1083 {
1084   return mysql->warning_count;
1085 }
1086 
1087 const char *STDCALL mysql_info(MYSQL *mysql)
1088 {
1089   return mysql->info;
1090 }
1091 
1092 ulong STDCALL mysql_thread_id(MYSQL *mysql)
1093 {
1094   return (mysql)->thread_id;
1095 }
1096 
1097 const char * STDCALL mysql_character_set_name(MYSQL *mysql)
1098 {
1099   return mysql->charset->csname;
1100 }
1101 
1102 void STDCALL mysql_get_character_set_info(MYSQL *mysql, MY_CHARSET_INFO *csinfo)
1103 {
1104   csinfo->number   = mysql->charset->number;
1105   csinfo->state    = mysql->charset->state;
1106   csinfo->csname   = mysql->charset->csname;
1107   csinfo->name     = mysql->charset->name;
1108   csinfo->comment  = mysql->charset->comment;
1109   csinfo->mbminlen = mysql->charset->mbminlen;
1110   csinfo->mbmaxlen = mysql->charset->mbmaxlen;
1111 
1112   if (mysql->options.charset_dir)
1113     csinfo->dir = mysql->options.charset_dir;
1114   else
1115     csinfo->dir = charsets_dir;
1116 }
1117 
1118 uint STDCALL mysql_thread_safe(void)
1119 {
1120   return 1;
1121 }
1122 
1123 
1124 my_bool STDCALL mysql_embedded(void)
1125 {
1126 #ifdef EMBEDDED_LIBRARY
1127   return 1;
1128 #else
1129   return 0;
1130 #endif
1131 }
1132 
1133 /****************************************************************************
1134   Some support functions
1135 ****************************************************************************/
1136 
1137 /*
1138   Functions called my my_net_init() to set some application specific variables
1139 */
1140 
1141 void my_net_local_init(NET *net)
1142 {
1143   net->max_packet=   (uint) net_buffer_length;
1144   net->read_timeout= net->write_timeout= 0;
1145   my_net_set_read_timeout(net, CLIENT_NET_READ_TIMEOUT);
1146   my_net_set_write_timeout(net, CLIENT_NET_WRITE_TIMEOUT);
1147   net->retry_count=  1;
1148   net->max_packet_size= MY_MAX(net_buffer_length, max_allowed_packet);
1149 }
1150 
1151 /*
1152   This function is used to create HEX string that you
1153   can use in a SQL statement in of the either ways:
1154     INSERT INTO blob_column VALUES (0xAABBCC);  (any MySQL version)
1155     INSERT INTO blob_column VALUES (X'AABBCC'); (4.1 and higher)
1156 
1157   The string in "from" is encoded to a HEX string.
1158   The result is placed in "to" and a terminating null byte is appended.
1159 
1160   The string pointed to by "from" must be "length" bytes long.
1161   You must allocate the "to" buffer to be at least length*2+1 bytes long.
1162   Each character needs two bytes, and you need room for the terminating
1163   null byte. When mysql_hex_string() returns, the contents of "to" will
1164   be a null-terminated string. The return value is the length of the
1165   encoded string, not including the terminating null character.
1166 
1167   The return value does not contain any leading 0x or a leading X' and
1168   trailing '. The caller must supply whichever of those is desired.
1169 */
1170 
1171 ulong STDCALL
1172 mysql_hex_string(char *to, const char *from, ulong length)
1173 {
1174   char *to0= to;
1175   const char *end;
1176 
1177   for (end= from + length; from < end; from++)
1178   {
1179     *to++= _dig_vec_upper[((unsigned char) *from) >> 4];
1180     *to++= _dig_vec_upper[((unsigned char) *from) & 0x0F];
1181   }
1182   *to= '\0';
1183   return (ulong) (to-to0);
1184 }
1185 
1186 /*
1187   Add escape characters to a string (blob?) to make it suitable for a insert
1188   to should at least have place for length*2+1 chars
1189   Returns the length of the to string
1190 */
1191 
1192 ulong STDCALL
1193 mysql_escape_string(char *to,const char *from,ulong length)
1194 {
1195   return (uint) escape_string_for_mysql(default_charset_info, to, 0, from, length);
1196 }
1197 
1198 ulong STDCALL
1199 mysql_real_escape_string(MYSQL *mysql, char *to,const char *from,
1200 			 ulong length)
1201 {
1202   if (mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES)
1203     return (uint) escape_quotes_for_mysql(mysql->charset, to, 0, from, length);
1204   return (uint) escape_string_for_mysql(mysql->charset, to, 0, from, length);
1205 }
1206 
1207 void STDCALL
1208 myodbc_remove_escape(MYSQL *mysql,char *name)
1209 {
1210   char *to;
1211 #ifdef USE_MB
1212   my_bool use_mb_flag=use_mb(mysql->charset);
1213   char *UNINIT_VAR(end);
1214   if (use_mb_flag)
1215     for (end=name; *end ; end++) ;
1216 #endif
1217 
1218   for (to=name ; *name ; name++)
1219   {
1220 #ifdef USE_MB
1221     int l;
1222     if (use_mb_flag && (l = my_ismbchar( mysql->charset, name , end ) ) )
1223     {
1224       while (l--)
1225 	*to++ = *name++;
1226       name--;
1227       continue;
1228     }
1229 #endif
1230     if (*name == '\\' && name[1])
1231       name++;
1232     *to++= *name;
1233   }
1234   *to=0;
1235 }
1236 
1237 /********************************************************************
1238  Implementation of new client API for 4.1 version.
1239 
1240  mysql_stmt_* are real prototypes used by applications.
1241 
1242  To make API work in embedded library all functions performing
1243  real I/O are prefixed with 'cli_' (abbreviated from 'Call Level
1244  Interface'). This functions are invoked via pointers set in
1245  MYSQL::methods structure. Embedded counterparts, prefixed with
1246  'emb_' reside in libmysqld/lib_sql.cc.
1247 *********************************************************************/
1248 
1249 /******************* Declarations ***********************************/
1250 
1251 /* Default number of rows fetched per one COM_STMT_FETCH command. */
1252 
1253 #define DEFAULT_PREFETCH_ROWS (ulong) 1
1254 
1255 /*
1256   These functions are called by function pointer MYSQL_STMT::read_row_func.
1257   Each function corresponds to one of the read methods:
1258   - mysql_stmt_fetch without prior mysql_stmt_store_result,
1259   - mysql_stmt_fetch when result is stored,
1260   - mysql_stmt_fetch when there are no rows (always returns MYSQL_NO_DATA)
1261 */
1262 
1263 static int stmt_read_row_unbuffered(MYSQL_STMT *stmt, unsigned char **row);
1264 static int stmt_read_row_buffered(MYSQL_STMT *stmt, unsigned char **row);
1265 static int stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row);
1266 static int stmt_read_row_no_data(MYSQL_STMT *stmt, unsigned char **row);
1267 static int stmt_read_row_no_result_set(MYSQL_STMT *stmt, unsigned char **row);
1268 
1269 /*
1270   This function is used in mysql_stmt_store_result if
1271   STMT_ATTR_UPDATE_MAX_LENGTH attribute is set.
1272 */
1273 static void stmt_update_metadata(MYSQL_STMT *stmt, MYSQL_ROWS *data);
1274 static my_bool setup_one_fetch_function(MYSQL_BIND *, MYSQL_FIELD *field);
1275 
1276 /* Auxiliary function used to reset statement handle. */
1277 
1278 #define RESET_SERVER_SIDE 1
1279 #define RESET_LONG_DATA 2
1280 #define RESET_STORE_RESULT 4
1281 #define RESET_CLEAR_ERROR 8
1282 #define RESET_ALL_BUFFERS 16
1283 
1284 static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags);
1285 
1286 /*
1287   Maximum sizes of MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME
1288   values stored in network buffer.
1289 */
1290 
1291 /* 1 (length) + 2 (year) + 1 (month) + 1 (day) */
1292 #define MAX_DATE_REP_LENGTH 5
1293 
1294 /*
1295   1 (length) + 1 (is negative) + 4 (day count) + 1 (hour)
1296   + 1 (minute) + 1 (seconds) + 4 (microseconds)
1297 */
1298 #define MAX_TIME_REP_LENGTH 13
1299 
1300 /*
1301   1 (length) + 2 (year) + 1 (month) + 1 (day) +
1302   1 (hour) + 1 (minute) + 1 (second) + 4 (microseconds)
1303 */
1304 #define MAX_DATETIME_REP_LENGTH 12
1305 
1306 #define MAX_DOUBLE_STRING_REP_LENGTH 331
1307 
1308 /* A macro to check truncation errors */
1309 
1310 #define IS_TRUNCATED(value, is_unsigned, min, max, umax) \
1311         ((is_unsigned) ? (((value) > (umax) || (value) < 0) ? 1 : 0) : \
1312                          (((value) > (max)  || (value) < (min)) ? 1 : 0))
1313 
1314 #define BIND_RESULT_DONE 1
1315 /*
1316   We report truncations only if at least one of MYSQL_BIND::error
1317   pointers is set. In this case stmt->bind_result_done |-ed with
1318   this flag.
1319 */
1320 #define REPORT_DATA_TRUNCATION 2
1321 
1322 /**************** Misc utility functions ****************************/
1323 
1324 /*
1325   Reallocate the NET package to have at least length bytes available.
1326 
1327   SYNPOSIS
1328     my_realloc_str()
1329     net                 The NET structure to modify.
1330     length              Ensure that net->buff has space for at least
1331                         this number of bytes.
1332 
1333   RETURN VALUES
1334     0   Success.
1335     1   Error, i.e. out of memory or requested packet size is bigger
1336         than max_allowed_packet. The error code is stored in net->last_errno.
1337 */
1338 
1339 static my_bool my_realloc_str(NET *net, ulong length)
1340 {
1341   ulong buf_length= (ulong) (net->write_pos - net->buff);
1342   my_bool res=0;
1343   DBUG_ENTER("my_realloc_str");
1344   if (buf_length + length > net->max_packet)
1345   {
1346     res= net_realloc(net, buf_length + length);
1347     if (res)
1348     {
1349       if (net->last_errno == ER_OUT_OF_RESOURCES)
1350         net->last_errno= CR_OUT_OF_MEMORY;
1351       else if (net->last_errno == ER_NET_PACKET_TOO_LARGE)
1352         net->last_errno= CR_NET_PACKET_TOO_LARGE;
1353       strmov(net->sqlstate, unknown_sqlstate);
1354       strmov(net->last_error, ER(net->last_errno));
1355     }
1356     net->write_pos= net->buff+ buf_length;
1357   }
1358   DBUG_RETURN(res);
1359 }
1360 
1361 
1362 static void stmt_clear_error(MYSQL_STMT *stmt)
1363 {
1364   if (stmt->last_errno)
1365   {
1366     stmt->last_errno= 0;
1367     stmt->last_error[0]= '\0';
1368     strmov(stmt->sqlstate, not_error_sqlstate);
1369   }
1370 }
1371 
1372 /**
1373   Set statement error code, sqlstate, and error message
1374   from given errcode and sqlstate.
1375 */
1376 
1377 void set_stmt_error(MYSQL_STMT * stmt, int errcode,
1378                     const char *sqlstate, const char *err)
1379 {
1380   DBUG_ENTER("set_stmt_error");
1381   DBUG_PRINT("enter", ("error: %d '%s'", errcode, ER(errcode)));
1382   DBUG_ASSERT(stmt != 0);
1383 
1384   if (err == 0)
1385     err= ER(errcode);
1386 
1387   stmt->last_errno= errcode;
1388   strmov(stmt->last_error, ER(errcode));
1389   strmov(stmt->sqlstate, sqlstate);
1390 
1391   DBUG_VOID_RETURN;
1392 }
1393 
1394 
1395 /**
1396   Set statement error code, sqlstate, and error message from NET.
1397 
1398   @param stmt  a statement handle. Copy the error here.
1399   @param net   mysql->net. Source of the error.
1400 */
1401 
1402 void set_stmt_errmsg(MYSQL_STMT *stmt, NET *net)
1403 {
1404   DBUG_ENTER("set_stmt_errmsg");
1405   DBUG_PRINT("enter", ("error: %d/%s '%s'",
1406                        net->last_errno,
1407                        net->sqlstate,
1408                        net->last_error));
1409   DBUG_ASSERT(stmt != 0);
1410 
1411   stmt->last_errno= net->last_errno;
1412   if (net->last_error[0])
1413     strmov(stmt->last_error, net->last_error);
1414   strmov(stmt->sqlstate, net->sqlstate);
1415 
1416   DBUG_VOID_RETURN;
1417 }
1418 
1419 /*
1420   Read and unpack server reply to COM_STMT_PREPARE command (sent from
1421   mysql_stmt_prepare).
1422 
1423   SYNOPSIS
1424     cli_read_prepare_result()
1425     mysql   connection handle
1426     stmt    statement handle
1427 
1428   RETURN VALUES
1429     0	ok
1430     1	error
1431 */
1432 
1433 my_bool cli_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt)
1434 {
1435   uchar *pos;
1436   uint field_count, param_count;
1437   ulong packet_length;
1438   MYSQL_DATA *fields_data;
1439   DBUG_ENTER("cli_read_prepare_result");
1440 
1441   if ((packet_length= cli_safe_read(mysql)) == packet_error)
1442     DBUG_RETURN(1);
1443   mysql->warning_count= 0;
1444 
1445   pos= (uchar*) mysql->net.read_pos;
1446   stmt->stmt_id= uint4korr(pos+1); pos+= 5;
1447   /* Number of columns in result set */
1448   field_count=   uint2korr(pos);   pos+= 2;
1449   /* Number of placeholders in the statement */
1450   param_count=   uint2korr(pos);   pos+= 2;
1451   if (packet_length >= 12)
1452     mysql->warning_count= uint2korr(pos+1);
1453 
1454   if (param_count != 0)
1455   {
1456     MYSQL_DATA *param_data;
1457 
1458     /* skip parameters data: we don't support it yet */
1459     if (!(param_data= (*mysql->methods->read_rows)(mysql, (MYSQL_FIELD*)0, 7)))
1460       DBUG_RETURN(1);
1461     free_rows(param_data);
1462   }
1463 
1464   if (field_count != 0)
1465   {
1466     if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
1467       mysql->server_status|= SERVER_STATUS_IN_TRANS;
1468 
1469     if (!(fields_data= (*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*)0,7)))
1470       DBUG_RETURN(1);
1471     if (!(stmt->fields= unpack_fields(mysql, fields_data,&stmt->mem_root,
1472 				      field_count,0,
1473 				      mysql->server_capabilities)))
1474       DBUG_RETURN(1);
1475   }
1476   stmt->field_count=  field_count;
1477   stmt->param_count=  (ulong) param_count;
1478   DBUG_PRINT("exit",("field_count: %u  param_count: %u  warning_count: %u",
1479                      field_count, param_count, (uint) mysql->warning_count));
1480 
1481   DBUG_RETURN(0);
1482 }
1483 
1484 
1485 /*
1486   Allocate memory and init prepared statement structure.
1487 
1488   SYNOPSIS
1489     mysql_stmt_init()
1490     mysql   connection handle
1491 
1492   DESCRIPTION
1493     This is an entry point of the new API. Returned handle stands for
1494     a server-side prepared statement. Memory for this structure (~700
1495     bytes) is allocated using 'malloc'. Once created, the handle can be
1496     reused many times. Created statement handle is bound to connection
1497     handle provided to this call: its lifetime is limited by lifetime
1498     of connection.
1499     'mysql_stmt_init()' is a pure local call, server side structure is
1500     created only in mysql_stmt_prepare.
1501     Next steps you may want to make:
1502     - set a statement attribute (mysql_stmt_attr_set()),
1503     - prepare statement handle with a query (mysql_stmt_prepare()),
1504     - close statement handle and free its memory (mysql_stmt_close()),
1505     - reset statement with mysql_stmt_reset() (a no-op which will
1506       just return).
1507     Behaviour of the rest of API calls on this statement is not defined yet
1508     (though we're working on making each wrong call sequence return
1509     error).
1510 
1511   RETURN VALUE
1512     statement structure upon success and NULL if out of
1513     memory
1514 */
1515 
1516 #ifdef EMBEDDED_LIBRARY
1517 #undef MY_THREAD_SPECIFIC
1518 #define MY_THREAD_SPECIFIC 0
1519 #endif /*EMBEDDED_LIBRARY*/
1520 
1521 MYSQL_STMT * STDCALL
1522 mysql_stmt_init(MYSQL *mysql)
1523 {
1524   MYSQL_STMT *stmt;
1525   DBUG_ENTER("mysql_stmt_init");
1526 
1527   if (!(stmt=
1528           (MYSQL_STMT *) my_malloc(sizeof (MYSQL_STMT),
1529                                    MYF(MY_WME | MY_ZEROFILL))) ||
1530       !(stmt->extension=
1531           (MYSQL_STMT_EXT *) my_malloc(sizeof (MYSQL_STMT_EXT),
1532                                        MYF(MY_WME | MY_ZEROFILL))))
1533   {
1534     set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
1535     my_free(stmt);
1536     DBUG_RETURN(NULL);
1537   }
1538 
1539   init_alloc_root(&stmt->mem_root, "stmt", 2048,2048, MYF(MY_THREAD_SPECIFIC));
1540   init_alloc_root(&stmt->result.alloc, "result", 4096, 4096,
1541                   MYF(MY_THREAD_SPECIFIC));
1542   stmt->result.alloc.min_malloc= sizeof(MYSQL_ROWS);
1543   mysql->stmts= list_add(mysql->stmts, &stmt->list);
1544   stmt->list.data= stmt;
1545   stmt->state= MYSQL_STMT_INIT_DONE;
1546   stmt->mysql= mysql;
1547   stmt->read_row_func= stmt_read_row_no_result_set;
1548   stmt->prefetch_rows= DEFAULT_PREFETCH_ROWS;
1549   strmov(stmt->sqlstate, not_error_sqlstate);
1550   /* The rest of statement members was bzeroed inside malloc */
1551 
1552   init_alloc_root(&stmt->extension->fields_mem_root, "extension", 2048, 0,
1553                   MYF(MY_THREAD_SPECIFIC));
1554 
1555   DBUG_RETURN(stmt);
1556 }
1557 
1558 
1559 /*
1560   Prepare server side statement with query.
1561 
1562   SYNOPSIS
1563     mysql_stmt_prepare()
1564     stmt    statement handle
1565     query   statement to prepare
1566     length  statement length
1567 
1568   DESCRIPTION
1569     Associate statement with statement handle. This is done both on
1570     client and server sides. At this point the server parses given query
1571     and creates an internal structure to represent it.
1572     Next steps you may want to make:
1573     - find out if this statement returns a result set by
1574       calling mysql_stmt_field_count(), and get result set metadata
1575       with mysql_stmt_result_metadata(),
1576     - if query contains placeholders, bind input parameters to placeholders
1577       using mysql_stmt_bind_param(),
1578     - otherwise proceed directly to mysql_stmt_execute().
1579 
1580   IMPLEMENTATION NOTES
1581   - if this is a re-prepare of the statement, first close previous data
1582     structure on the server and free old statement data
1583   - then send the query to server and get back number of placeholders,
1584     number of columns in result set (if any), and result set metadata.
1585     At the same time allocate memory for input and output parameters
1586     to have less checks in mysql_stmt_bind_{param, result}.
1587 
1588   RETURN VALUES
1589     0  success
1590    !0  error
1591 */
1592 
1593 int STDCALL
1594 mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
1595 {
1596   MYSQL *mysql= stmt->mysql;
1597   DBUG_ENTER("mysql_stmt_prepare");
1598 
1599   if (!mysql)
1600   {
1601     /* mysql can be reset in mysql_close called from mysql_reconnect */
1602     set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL);
1603     DBUG_RETURN(1);
1604   }
1605 
1606   /*
1607     Reset the last error in any case: that would clear the statement
1608     if the previous prepare failed.
1609   */
1610   stmt->last_errno= 0;
1611   stmt->last_error[0]= '\0';
1612 
1613   if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE)
1614   {
1615     /* This is second prepare with another statement */
1616     uchar buff[MYSQL_STMT_HEADER];               /* 4 bytes - stmt id */
1617 
1618     if (reset_stmt_handle(stmt, RESET_LONG_DATA | RESET_STORE_RESULT))
1619       DBUG_RETURN(1);
1620     /*
1621       These members must be reset for API to
1622       function in case of error or misuse.
1623     */
1624     stmt->bind_param_done= stmt->bind_result_done= FALSE;
1625     stmt->param_count= stmt->field_count= 0;
1626     free_root(&stmt->mem_root, MYF(MY_KEEP_PREALLOC));
1627     free_root(&stmt->extension->fields_mem_root, MYF(0));
1628 
1629     int4store(buff, stmt->stmt_id);
1630 
1631     /*
1632       Close statement in server
1633 
1634       If there was a 'use' result from another statement, or from
1635       mysql_use_result it won't be freed in mysql_stmt_free_result and
1636       we should get 'Commands out of sync' here.
1637     */
1638     stmt->state= MYSQL_STMT_INIT_DONE;
1639     if (stmt_command(mysql, COM_STMT_CLOSE, buff, 4, stmt))
1640     {
1641       set_stmt_errmsg(stmt, &mysql->net);
1642       DBUG_RETURN(1);
1643     }
1644   }
1645 
1646   if (stmt_command(mysql, COM_STMT_PREPARE, (const uchar*) query, length, stmt))
1647   {
1648     set_stmt_errmsg(stmt, &mysql->net);
1649     DBUG_RETURN(1);
1650   }
1651 
1652   if ((*mysql->methods->read_prepare_result)(mysql, stmt))
1653   {
1654     set_stmt_errmsg(stmt, &mysql->net);
1655     DBUG_RETURN(1);
1656   }
1657 
1658   /*
1659     alloc_root will return valid address even in case when param_count
1660     and field_count are zero. Thus we should never rely on stmt->bind
1661     or stmt->params when checking for existence of placeholders or
1662     result set.
1663   */
1664   if (!(stmt->params= (MYSQL_BIND *) alloc_root(&stmt->mem_root,
1665 						sizeof(MYSQL_BIND)*
1666                                                 (stmt->param_count +
1667                                                  stmt->field_count))))
1668   {
1669     set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL);
1670     DBUG_RETURN(1);
1671   }
1672   stmt->bind= stmt->params + stmt->param_count;
1673   stmt->state= MYSQL_STMT_PREPARE_DONE;
1674   DBUG_PRINT("info", ("Parameter count: %u", stmt->param_count));
1675   DBUG_RETURN(0);
1676 }
1677 
1678 /*
1679   Get result set metadata from reply to mysql_stmt_execute.
1680   This is used mainly for SHOW commands, as metadata for these
1681   commands is sent only with result set.
1682   To be removed when all commands will fully support prepared mode.
1683 */
1684 
1685 static void alloc_stmt_fields(MYSQL_STMT *stmt)
1686 {
1687   MYSQL_FIELD *fields, *field, *end;
1688   MEM_ROOT *fields_mem_root= &stmt->extension->fields_mem_root;
1689   MYSQL *mysql= stmt->mysql;
1690 
1691   DBUG_ASSERT(stmt->field_count);
1692 
1693   free_root(fields_mem_root, MYF(0));
1694 
1695   /*
1696     Get the field information for non-select statements
1697     like SHOW and DESCRIBE commands
1698   */
1699   if (!(stmt->fields= (MYSQL_FIELD *) alloc_root(fields_mem_root,
1700 						 sizeof(MYSQL_FIELD) *
1701 						 stmt->field_count)) ||
1702       !(stmt->bind= (MYSQL_BIND *) alloc_root(fields_mem_root,
1703 					      sizeof(MYSQL_BIND) *
1704 					      stmt->field_count)))
1705   {
1706     set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL);
1707     return;
1708   }
1709 
1710   for (fields= mysql->fields, end= fields+stmt->field_count,
1711 	 field= stmt->fields;
1712        field && fields < end; fields++, field++)
1713   {
1714     *field= *fields; /* To copy all numeric parts. */
1715     field->catalog=   strmake_root(fields_mem_root,
1716                                    fields->catalog,
1717                                    fields->catalog_length);
1718     field->db=        strmake_root(fields_mem_root,
1719                                    fields->db,
1720                                    fields->db_length);
1721     field->table=     strmake_root(fields_mem_root,
1722                                    fields->table,
1723                                    fields->table_length);
1724     field->org_table= strmake_root(fields_mem_root,
1725                                    fields->org_table,
1726                                    fields->org_table_length);
1727     field->name=      strmake_root(fields_mem_root,
1728                                    fields->name,
1729                                    fields->name_length);
1730     field->org_name=  strmake_root(fields_mem_root,
1731                                    fields->org_name,
1732                                    fields->org_name_length);
1733     if (fields->def)
1734     {
1735       field->def= strmake_root(fields_mem_root,
1736                                fields->def,
1737                                fields->def_length);
1738       field->def_length= fields->def_length;
1739     }
1740     else
1741     {
1742       field->def= NULL;
1743       field->def_length= 0;
1744     }
1745     field->extension= 0; /* Avoid dangling links. */
1746     field->max_length= 0; /* max_length is set in mysql_stmt_store_result() */
1747   }
1748 }
1749 
1750 
1751 /**
1752   Update result set columns metadata if it was sent again in
1753   reply to COM_STMT_EXECUTE.
1754 
1755   @note If the new field count is different from the original one,
1756         an error is set and no update is performed.
1757 */
1758 
1759 static void update_stmt_fields(MYSQL_STMT *stmt)
1760 {
1761   MYSQL_FIELD *field= stmt->mysql->fields;
1762   MYSQL_FIELD *field_end= field + stmt->field_count;
1763   MYSQL_FIELD *stmt_field= stmt->fields;
1764   MYSQL_BIND *my_bind= stmt->bind_result_done ? stmt->bind : 0;
1765 
1766   if (stmt->field_count != stmt->mysql->field_count)
1767   {
1768     /*
1769       The tables used in the statement were altered,
1770       and the query now returns a different number of columns.
1771       There is no way to continue without reallocating the bind
1772       array:
1773       - if the number of columns increased, mysql_stmt_fetch()
1774       will write beyond allocated memory
1775       - if the number of columns decreased, some user-bound
1776       buffers will be left unassigned without user knowing
1777       that.
1778     */
1779     set_stmt_error(stmt, CR_NEW_STMT_METADATA, unknown_sqlstate, NULL);
1780     return;
1781   }
1782 
1783   for (; field < field_end; ++field, ++stmt_field)
1784   {
1785     stmt_field->charsetnr= field->charsetnr;
1786     stmt_field->length   = field->length;
1787     stmt_field->type     = field->type;
1788     stmt_field->flags    = field->flags;
1789     stmt_field->decimals = field->decimals;
1790     if (my_bind)
1791     {
1792       /* Ignore return value: it should be 0 if bind_result succeeded. */
1793       (void) setup_one_fetch_function(my_bind++, stmt_field);
1794     }
1795   }
1796 }
1797 
1798 /*
1799   Returns prepared statement metadata in the form of a result set.
1800 
1801   SYNOPSIS
1802     mysql_stmt_result_metadata()
1803     stmt  statement handle
1804 
1805   DESCRIPTION
1806     This function should be used after mysql_stmt_execute().
1807     You can safely check that prepared statement has a result set by calling
1808     mysql_stmt_field_count(): if number of fields is not zero, you can call
1809     this function to get fields metadata.
1810     Next steps you may want to make:
1811     - find out number of columns in result set by calling
1812       mysql_num_fields(res) (the same value is returned by
1813       mysql_stmt_field_count())
1814     - fetch metadata for any column with mysql_fetch_field,
1815       mysql_fetch_field_direct, mysql_fetch_fields, mysql_field_seek.
1816     - free returned MYSQL_RES structure with mysql_free_result.
1817     - proceed to binding of output parameters.
1818 
1819   RETURN
1820     NULL  statement contains no result set or out of memory.
1821           In the latter case you can retrieve error message
1822           with mysql_stmt_error.
1823     MYSQL_RES  a result set with no rows
1824 */
1825 
1826 MYSQL_RES * STDCALL
1827 mysql_stmt_result_metadata(MYSQL_STMT *stmt)
1828 {
1829   MYSQL_RES *result;
1830   DBUG_ENTER("mysql_stmt_result_metadata");
1831 
1832   /*
1833     stmt->fields is only defined if stmt->field_count is not null;
1834     stmt->field_count is initialized in prepare.
1835   */
1836   if (!stmt->field_count)
1837      DBUG_RETURN(0);
1838 
1839   if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result),
1840                                       MYF(MY_WME | MY_ZEROFILL))))
1841   {
1842     set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL);
1843     DBUG_RETURN(0);
1844   }
1845 
1846   result->methods=	stmt->mysql->methods;
1847   result->eof=		1;                      /* Marker for buffered */
1848   result->fields=	stmt->fields;
1849   result->field_count=	stmt->field_count;
1850   /* The rest of members of 'result' was bzeroed inside malloc */
1851   DBUG_RETURN(result);
1852 }
1853 
1854 
1855 /*
1856   Returns parameter columns meta information in the form of
1857   result set.
1858 
1859   SYNOPSIS
1860     mysql_stmt_param_metadata()
1861     stmt    statement handle
1862 
1863   DESCRIPTION
1864     This function can be called after you prepared the statement handle
1865     with mysql_stmt_prepare().
1866     XXX: not implemented yet.
1867 
1868   RETURN
1869     MYSQL_RES on success, 0 if there is no metadata.
1870     Currently this function always returns 0.
1871 */
1872 
1873 MYSQL_RES * STDCALL
1874 mysql_stmt_param_metadata(MYSQL_STMT *stmt)
1875 {
1876   DBUG_ENTER("mysql_stmt_param_metadata");
1877 
1878   if (!stmt->param_count)
1879     DBUG_RETURN(0);
1880 
1881   /*
1882     TODO: Fix this when server sends the information.
1883     Till then keep a dummy prototype.
1884   */
1885   DBUG_RETURN(0);
1886 }
1887 
1888 
1889 /* Store type of parameter in network buffer. */
1890 
1891 static void store_param_type(unsigned char **pos, MYSQL_BIND *param)
1892 {
1893   uint typecode= param->buffer_type | (param->is_unsigned ? 32768 : 0);
1894   int2store(*pos, typecode);
1895   *pos+= 2;
1896 }
1897 
1898 
1899 /*
1900   Functions to store parameter data in network packet.
1901 
1902   SYNOPSIS
1903     store_param_xxx()
1904     net			MySQL NET connection
1905     param		MySQL bind param
1906 
1907   DESCRIPTION
1908     These functions are invoked from mysql_stmt_execute() by
1909     MYSQL_BIND::store_param_func pointer. This pointer is set once per
1910     many executions in mysql_stmt_bind_param(). The caller must ensure
1911     that network buffer have enough capacity to store parameter
1912     (MYSQL_BIND::buffer_length contains needed number of bytes).
1913 */
1914 
1915 static void store_param_tinyint(NET *net, MYSQL_BIND *param)
1916 {
1917   *(net->write_pos++)= *(uchar *) param->buffer;
1918 }
1919 
1920 static void store_param_short(NET *net, MYSQL_BIND *param)
1921 {
1922   short value= *(short*) param->buffer;
1923   int2store(net->write_pos,value);
1924   net->write_pos+=2;
1925 }
1926 
1927 static void store_param_int32(NET *net, MYSQL_BIND *param)
1928 {
1929   int32 value= *(int32*) param->buffer;
1930   int4store(net->write_pos,value);
1931   net->write_pos+=4;
1932 }
1933 
1934 static void store_param_int64(NET *net, MYSQL_BIND *param)
1935 {
1936   longlong value= *(longlong*) param->buffer;
1937   int8store(net->write_pos,value);
1938   net->write_pos+= 8;
1939 }
1940 
1941 static void store_param_float(NET *net, MYSQL_BIND *param)
1942 {
1943   float value= *(float*) param->buffer;
1944   float4store(net->write_pos, value);
1945   net->write_pos+= 4;
1946 }
1947 
1948 static void store_param_double(NET *net, MYSQL_BIND *param)
1949 {
1950   double value= *(double*) param->buffer;
1951   float8store(net->write_pos, value);
1952   net->write_pos+= 8;
1953 }
1954 
1955 static void store_param_time(NET *net, MYSQL_BIND *param)
1956 {
1957   MYSQL_TIME *tm= (MYSQL_TIME *) param->buffer;
1958   char buff[MAX_TIME_REP_LENGTH], *pos;
1959   uint length;
1960 
1961   pos= buff+1;
1962   pos[0]= tm->neg ? 1: 0;
1963   int4store(pos+1, tm->day);
1964   pos[5]= (uchar) tm->hour;
1965   pos[6]= (uchar) tm->minute;
1966   pos[7]= (uchar) tm->second;
1967   int4store(pos+8, tm->second_part);
1968   if (tm->second_part)
1969     length= 12;
1970   else if (tm->hour || tm->minute || tm->second || tm->day)
1971     length= 8;
1972   else
1973     length= 0;
1974   buff[0]= (char) length++;
1975   memcpy((char *)net->write_pos, buff, length);
1976   net->write_pos+= length;
1977 }
1978 
1979 static void net_store_datetime(NET *net, MYSQL_TIME *tm)
1980 {
1981   char buff[MAX_DATETIME_REP_LENGTH], *pos;
1982   uint length;
1983 
1984   pos= buff+1;
1985 
1986   int2store(pos, tm->year);
1987   pos[2]= (uchar) tm->month;
1988   pos[3]= (uchar) tm->day;
1989   pos[4]= (uchar) tm->hour;
1990   pos[5]= (uchar) tm->minute;
1991   pos[6]= (uchar) tm->second;
1992   int4store(pos+7, tm->second_part);
1993   if (tm->second_part)
1994     length= 11;
1995   else if (tm->hour || tm->minute || tm->second)
1996     length= 7;
1997   else if (tm->year || tm->month || tm->day)
1998     length= 4;
1999   else
2000     length= 0;
2001   buff[0]= (char) length++;
2002   memcpy((char *)net->write_pos, buff, length);
2003   net->write_pos+= length;
2004 }
2005 
2006 static void store_param_date(NET *net, MYSQL_BIND *param)
2007 {
2008   MYSQL_TIME tm= *((MYSQL_TIME *) param->buffer);
2009   tm.hour= tm.minute= tm.second= tm.second_part= 0;
2010   net_store_datetime(net, &tm);
2011 }
2012 
2013 static void store_param_datetime(NET *net, MYSQL_BIND *param)
2014 {
2015   MYSQL_TIME *tm= (MYSQL_TIME *) param->buffer;
2016   net_store_datetime(net, tm);
2017 }
2018 
2019 static void store_param_str(NET *net, MYSQL_BIND *param)
2020 {
2021   /* param->length is always set in mysql_stmt_bind_param */
2022   ulong length= *param->length;
2023   uchar *to= net_store_length(net->write_pos, length);
2024   memcpy(to, param->buffer, length);
2025   net->write_pos= to+length;
2026 }
2027 
2028 
2029 /*
2030   Mark if the parameter is NULL.
2031 
2032   SYNOPSIS
2033     store_param_null()
2034     net			MySQL NET connection
2035     param		MySQL bind param
2036 
2037   DESCRIPTION
2038     A data package starts with a string of bits where we set a bit
2039     if a parameter is NULL. Unlike bit string in result set row, here
2040     we don't have reserved bits for OK/error packet.
2041 */
2042 
2043 static void store_param_null(NET *net, MYSQL_BIND *param)
2044 {
2045   uint pos= param->param_number;
2046   net->buff[pos/8]|=  (uchar) (1 << (pos & 7));
2047 }
2048 
2049 
2050 /*
2051   Store one parameter in network packet: data is read from
2052   client buffer and saved in network packet by means of one
2053   of store_param_xxxx functions.
2054 */
2055 
2056 static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param)
2057 {
2058   NET *net= &stmt->mysql->net;
2059   DBUG_ENTER("store_param");
2060   DBUG_PRINT("enter",("type: %d  buffer:%p  length: %lu  is_null: %d",
2061 		      param->buffer_type,
2062 		      param->buffer,
2063                       *param->length, *param->is_null));
2064 
2065   if (*param->is_null)
2066     store_param_null(net, param);
2067   else
2068   {
2069     /*
2070       Param->length should ALWAYS point to the correct length for the type
2071       Either to the length pointer given by the user or param->buffer_length
2072     */
2073     if ((my_realloc_str(net, *param->length)))
2074     {
2075       set_stmt_errmsg(stmt, net);
2076       DBUG_RETURN(1);
2077     }
2078     (*param->store_param_func)(net, param);
2079   }
2080   DBUG_RETURN(0);
2081 }
2082 
2083 
2084 /*
2085   Auxiliary function to send COM_STMT_EXECUTE packet to server and read reply.
2086   Used from cli_stmt_execute, which is in turn used by mysql_stmt_execute.
2087 */
2088 
2089 static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length)
2090 {
2091   MYSQL *mysql= stmt->mysql;
2092   NET	*net= &mysql->net;
2093   uchar buff[4 /* size of stmt id */ +
2094              5 /* execution flags */];
2095   my_bool res;
2096   DBUG_ENTER("execute");
2097   DBUG_DUMP("packet", (uchar *) packet, length);
2098 
2099   int4store(buff, stmt->stmt_id);		/* Send stmt id to server */
2100   buff[4]= (char) stmt->flags;
2101   int4store(buff+5, 1);                         /* iteration count */
2102 
2103   res= MY_TEST(cli_advanced_command(mysql, COM_STMT_EXECUTE, buff, sizeof(buff),
2104                                     (uchar*) packet, length, 1, stmt) ||
2105             (*mysql->methods->read_query_result)(mysql));
2106   stmt->affected_rows= mysql->affected_rows;
2107   stmt->server_status= mysql->server_status;
2108   stmt->insert_id= mysql->insert_id;
2109   if (res)
2110   {
2111     /*
2112       Don't set stmt error if stmt->mysql is NULL, as the error in this case
2113       has already been set by mysql_prune_stmt_list().
2114     */
2115     if (stmt->mysql)
2116       set_stmt_errmsg(stmt, net);
2117     DBUG_RETURN(1);
2118   }
2119   else if (mysql->status == MYSQL_STATUS_GET_RESULT)
2120     stmt->mysql->status= MYSQL_STATUS_STATEMENT_GET_RESULT;
2121   DBUG_RETURN(0);
2122 }
2123 
2124 
2125 int cli_stmt_execute(MYSQL_STMT *stmt)
2126 {
2127   DBUG_ENTER("cli_stmt_execute");
2128 
2129   if (stmt->param_count)
2130   {
2131     MYSQL *mysql= stmt->mysql;
2132     NET        *net= &mysql->net;
2133     MYSQL_BIND *param, *param_end;
2134     char       *param_data;
2135     ulong length;
2136     uint null_count;
2137     my_bool    result;
2138 
2139     if (!stmt->bind_param_done)
2140     {
2141       set_stmt_error(stmt, CR_PARAMS_NOT_BOUND, unknown_sqlstate, NULL);
2142       DBUG_RETURN(1);
2143     }
2144     if (mysql->status != MYSQL_STATUS_READY ||
2145         mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
2146     {
2147       set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, NULL);
2148       DBUG_RETURN(1);
2149     }
2150 
2151     if (net->vio)
2152       net_clear(net, 1);          /* Sets net->write_pos */
2153     else
2154     {
2155       set_stmt_errmsg(stmt, net);
2156       DBUG_RETURN(1);
2157     }
2158 
2159     /* Reserve place for null-marker bytes */
2160     null_count= (stmt->param_count+7) /8;
2161     if (my_realloc_str(net, null_count + 1))
2162     {
2163       set_stmt_errmsg(stmt, net);
2164       DBUG_RETURN(1);
2165     }
2166     bzero((char*) net->write_pos, null_count);
2167     net->write_pos+= null_count;
2168     param_end= stmt->params + stmt->param_count;
2169 
2170     /* In case if buffers (type) altered, indicate to server */
2171     *(net->write_pos)++= (uchar) stmt->send_types_to_server;
2172     if (stmt->send_types_to_server)
2173     {
2174       if (my_realloc_str(net, 2 * stmt->param_count))
2175       {
2176         set_stmt_errmsg(stmt, net);
2177         DBUG_RETURN(1);
2178       }
2179       /*
2180 	Store types of parameters in first in first package
2181 	that is sent to the server.
2182       */
2183       for (param= stmt->params;	param < param_end ; param++)
2184         store_param_type(&net->write_pos, param);
2185     }
2186 
2187     for (param= stmt->params; param < param_end; param++)
2188     {
2189       /* check if mysql_stmt_send_long_data() was used */
2190       if (param->long_data_used)
2191 	param->long_data_used= 0;	/* Clear for next execute call */
2192       else if (store_param(stmt, param))
2193 	DBUG_RETURN(1);
2194     }
2195     length= (ulong) (net->write_pos - net->buff);
2196     /* TODO: Look into avoding the following memdup */
2197     if (!(param_data= my_memdup(net->buff, length, MYF(0))))
2198     {
2199       set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL);
2200       DBUG_RETURN(1);
2201     }
2202     result= execute(stmt, param_data, length);
2203     stmt->send_types_to_server=0;
2204     my_free(param_data);
2205     DBUG_RETURN(result);
2206   }
2207   DBUG_RETURN((int) execute(stmt,0,0));
2208 }
2209 
2210 /*
2211   Read one row from buffered result set.  Result set is created by prior
2212   call to mysql_stmt_store_result().
2213   SYNOPSIS
2214     stmt_read_row_buffered()
2215 
2216   RETURN VALUE
2217     0             - success; *row is set to valid row pointer (row data
2218                     is stored in result set buffer)
2219     MYSQL_NO_DATA - end of result set. *row is set to NULL
2220 */
2221 
2222 static int stmt_read_row_buffered(MYSQL_STMT *stmt, unsigned char **row)
2223 {
2224   if (stmt->data_cursor)
2225   {
2226     *row= (uchar *) stmt->data_cursor->data;
2227     stmt->data_cursor= stmt->data_cursor->next;
2228     return 0;
2229   }
2230   *row= 0;
2231   return MYSQL_NO_DATA;
2232 }
2233 
2234 /*
2235   Read one row from network: unbuffered non-cursor fetch.
2236   If last row was read, or error occurred, erase this statement
2237   from record pointing to object unbuffered fetch is performed from.
2238 
2239   SYNOPSIS
2240     stmt_read_row_unbuffered()
2241     stmt  statement handle
2242     row   pointer to write pointer to row data;
2243 
2244   RETURN VALUE
2245     0           - success; *row contains valid address of a row;
2246                   row data is stored in network buffer
2247     1           - error; error code is written to
2248                   stmt->last_{errno,error}; *row is not changed
2249   MYSQL_NO_DATA - end of file was read from network;
2250                   *row is set to NULL
2251 */
2252 
2253 static int stmt_read_row_unbuffered(MYSQL_STMT *stmt, unsigned char **row)
2254 {
2255   int rc= 1;
2256   MYSQL *mysql= stmt->mysql;
2257   /*
2258     This function won't be called if stmt->field_count is zero
2259     or execution wasn't done: this is ensured by mysql_stmt_execute.
2260   */
2261   if (!mysql)
2262   {
2263     set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL);
2264     return 1;
2265   }
2266   if (mysql->status != MYSQL_STATUS_STATEMENT_GET_RESULT)
2267   {
2268     set_stmt_error(stmt, stmt->unbuffered_fetch_cancelled ?
2269                    CR_FETCH_CANCELED : CR_COMMANDS_OUT_OF_SYNC,
2270                    unknown_sqlstate, NULL);
2271     goto error;
2272   }
2273   if ((*mysql->methods->unbuffered_fetch)(mysql, (char**) row))
2274   {
2275     set_stmt_errmsg(stmt, &mysql->net);
2276     /*
2277       If there was an error, there are no more pending rows:
2278       reset statement status to not hang up in following
2279       mysql_stmt_close (it will try to flush result set before
2280       closing the statement).
2281     */
2282     mysql->status= MYSQL_STATUS_READY;
2283     goto error;
2284   }
2285   if (!*row)
2286   {
2287     mysql->status= MYSQL_STATUS_READY;
2288     rc= MYSQL_NO_DATA;
2289     goto error;
2290   }
2291   return 0;
2292 error:
2293   if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled)
2294     mysql->unbuffered_fetch_owner= 0;
2295   return rc;
2296 }
2297 
2298 
2299 /*
2300   Fetch statement row using server side cursor.
2301 
2302   SYNOPSIS
2303     stmt_read_row_from_cursor()
2304 
2305   RETURN VALUE
2306     0            success
2307     1            error
2308   MYSQL_NO_DATA  end of data
2309 */
2310 
2311 static int
2312 stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row)
2313 {
2314   if (stmt->data_cursor)
2315     return stmt_read_row_buffered(stmt, row);
2316   if (stmt->server_status & SERVER_STATUS_LAST_ROW_SENT)
2317     stmt->server_status &= ~SERVER_STATUS_LAST_ROW_SENT;
2318   else
2319   {
2320     MYSQL *mysql= stmt->mysql;
2321     NET *net= &mysql->net;
2322     MYSQL_DATA *result= &stmt->result;
2323     uchar buff[4 /* statement id */ +
2324                4 /* number of rows to fetch */];
2325 
2326     free_root(&result->alloc, MYF(MY_KEEP_PREALLOC));
2327     result->data= NULL;
2328     result->rows= 0;
2329     /* Send row request to the server */
2330     int4store(buff, stmt->stmt_id);
2331     int4store(buff + 4, stmt->prefetch_rows); /* number of rows to fetch */
2332     if ((*mysql->methods->advanced_command)(mysql, COM_STMT_FETCH,
2333                                             buff, sizeof(buff), (uchar*) 0, 0,
2334                                             1, stmt))
2335     {
2336       /*
2337         Don't set stmt error if stmt->mysql is NULL, as the error in this case
2338         has already been set by mysql_prune_stmt_list().
2339       */
2340       if (stmt->mysql)
2341         set_stmt_errmsg(stmt, net);
2342       return 1;
2343     }
2344     if ((*mysql->methods->read_rows_from_cursor)(stmt))
2345       return 1;
2346     stmt->server_status= mysql->server_status;
2347 
2348     stmt->data_cursor= result->data;
2349     return stmt_read_row_buffered(stmt, row);
2350   }
2351   *row= 0;
2352   return MYSQL_NO_DATA;
2353 }
2354 
2355 
2356 /*
2357   Default read row function to not SIGSEGV in client in
2358   case of wrong sequence of API calls.
2359 */
2360 
2361 static int
2362 stmt_read_row_no_data(MYSQL_STMT *stmt  __attribute__((unused)),
2363                       unsigned char **row  __attribute__((unused)))
2364 {
2365   return MYSQL_NO_DATA;
2366 }
2367 
2368 static int
2369 stmt_read_row_no_result_set(MYSQL_STMT *stmt  __attribute__((unused)),
2370                       unsigned char **row  __attribute__((unused)))
2371 {
2372   set_stmt_error(stmt, CR_NO_RESULT_SET, unknown_sqlstate, NULL);
2373   return 1;
2374 }
2375 
2376 
2377 /*
2378   Get/set statement attributes
2379 
2380   SYNOPSIS
2381     mysql_stmt_attr_get()
2382     mysql_stmt_attr_set()
2383 
2384     attr_type  statement attribute
2385     value      casted to const void * pointer to value.
2386 
2387   RETURN VALUE
2388     0 success
2389    !0 wrong attribute type
2390 */
2391 
2392 my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt,
2393                                     enum enum_stmt_attr_type attr_type,
2394                                     const void *value)
2395 {
2396   switch (attr_type) {
2397   case STMT_ATTR_UPDATE_MAX_LENGTH:
2398     stmt->update_max_length= value ? *(const my_bool*) value : 0;
2399     break;
2400   case STMT_ATTR_CURSOR_TYPE:
2401   {
2402     ulong cursor_type;
2403     cursor_type= value ? *(ulong*) value : 0UL;
2404     if (cursor_type > (ulong) CURSOR_TYPE_READ_ONLY)
2405       goto err_not_implemented;
2406     stmt->flags= cursor_type;
2407     break;
2408   }
2409   case STMT_ATTR_PREFETCH_ROWS:
2410   {
2411     ulong prefetch_rows= value ? *(ulong*) value : DEFAULT_PREFETCH_ROWS;
2412     if (value == 0)
2413       return TRUE;
2414     stmt->prefetch_rows= prefetch_rows;
2415     break;
2416   }
2417   default:
2418     goto err_not_implemented;
2419   }
2420   return FALSE;
2421 err_not_implemented:
2422   set_stmt_error(stmt, CR_NOT_IMPLEMENTED, unknown_sqlstate, NULL);
2423   return TRUE;
2424 }
2425 
2426 
2427 my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt,
2428                                     enum enum_stmt_attr_type attr_type,
2429                                     void *value)
2430 {
2431   switch (attr_type) {
2432   case STMT_ATTR_UPDATE_MAX_LENGTH:
2433     *(my_bool*) value= stmt->update_max_length;
2434     break;
2435   case STMT_ATTR_CURSOR_TYPE:
2436     *(ulong*) value= stmt->flags;
2437     break;
2438   case STMT_ATTR_PREFETCH_ROWS:
2439     *(ulong*) value= stmt->prefetch_rows;
2440     break;
2441   default:
2442     return TRUE;
2443   }
2444   return FALSE;
2445 }
2446 
2447 
2448 /**
2449   Update statement result set metadata from with the new field
2450   information sent during statement execute.
2451 
2452   @pre mysql->field_count is not zero
2453 
2454   @retval TRUE   if error: out of memory or the new
2455                  result set has a different number of columns
2456   @retval FALSE  success
2457 */
2458 
2459 static void reinit_result_set_metadata(MYSQL_STMT *stmt)
2460 {
2461   /* Server has sent result set metadata */
2462   if (stmt->field_count == 0)
2463   {
2464     /*
2465       This is 'SHOW'/'EXPLAIN'-like query. Current implementation of
2466       prepared statements can't send result set metadata for these queries
2467       on prepare stage. Read it now.
2468     */
2469 
2470     stmt->field_count= stmt->mysql->field_count;
2471 
2472     alloc_stmt_fields(stmt);
2473   }
2474   else
2475   {
2476     /*
2477       Update result set metadata if it for some reason changed between
2478       prepare and execute, i.e.:
2479       - in case of 'SELECT ?' we don't know column type unless data was
2480       supplied to mysql_stmt_execute, so updated column type is sent
2481       now.
2482       - if data dictionary changed between prepare and execute, for
2483       example a table used in the query was altered.
2484       Note, that now (4.1.3) we always send metadata in reply to
2485       COM_STMT_EXECUTE (even if it is not necessary), so either this or
2486       previous branch always works.
2487       TODO: send metadata only when it's really necessary and add a warning
2488       'Metadata changed' when it's sent twice.
2489     */
2490     update_stmt_fields(stmt);
2491   }
2492 }
2493 
2494 
2495 static void prepare_to_fetch_result(MYSQL_STMT *stmt)
2496 {
2497   if (stmt->server_status & SERVER_STATUS_CURSOR_EXISTS)
2498   {
2499     stmt->mysql->status= MYSQL_STATUS_READY;
2500     stmt->read_row_func= stmt_read_row_from_cursor;
2501   }
2502   else if (stmt->flags & CURSOR_TYPE_READ_ONLY)
2503   {
2504     /*
2505       This is a single-row result set, a result set with no rows, EXPLAIN,
2506       SHOW VARIABLES, or some other command which either a) bypasses the
2507       cursors framework in the server and writes rows directly to the
2508       network or b) is more efficient if all (few) result set rows are
2509       precached on client and server's resources are freed.
2510     */
2511     mysql_stmt_store_result(stmt);
2512   }
2513   else
2514   {
2515     stmt->mysql->unbuffered_fetch_owner= &stmt->unbuffered_fetch_cancelled;
2516     stmt->unbuffered_fetch_cancelled= FALSE;
2517     stmt->read_row_func= stmt_read_row_unbuffered;
2518   }
2519 }
2520 
2521 
2522 /*
2523   Send placeholders data to server (if there are placeholders)
2524   and execute prepared statement.
2525 
2526   SYNOPSIS
2527     mysql_stmt_execute()
2528     stmt  statement handle. The handle must be created
2529           with mysql_stmt_init() and prepared with
2530           mysql_stmt_prepare(). If there are placeholders
2531           in the statement they must be bound to local
2532           variables with mysql_stmt_bind_param().
2533 
2534   DESCRIPTION
2535     This function will automatically flush pending result
2536     set (if there is one), send parameters data to the server
2537     and read result of statement execution.
2538     If previous result set was cached with mysql_stmt_store_result()
2539     it will also be freed in the beginning of this call.
2540     The server can return 3 types of responses to this command:
2541     - error, can be retrieved with mysql_stmt_error()
2542     - ok, no result set pending. In this case we just update
2543       stmt->insert_id and stmt->affected_rows.
2544     - the query returns a result set: there could be 0 .. N
2545     rows in it. In this case the server can also send updated
2546     result set metadata.
2547 
2548     Next steps you may want to make:
2549     - find out if there is result set with mysql_stmt_field_count().
2550     If there is one:
2551     - optionally, cache entire result set on client to unblock
2552     connection with mysql_stmt_store_result()
2553     - bind client variables to result set columns and start read rows
2554     with mysql_stmt_fetch().
2555     - reset statement with mysql_stmt_reset() or close it with
2556     mysql_stmt_close()
2557     Otherwise:
2558     - find out last insert id and number of affected rows with
2559     mysql_stmt_insert_id(), mysql_stmt_affected_rows()
2560 
2561   RETURN
2562     0   success
2563     1   error, message can be retrieved with mysql_stmt_error().
2564 */
2565 
2566 int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
2567 {
2568   MYSQL *mysql= stmt->mysql;
2569   DBUG_ENTER("mysql_stmt_execute");
2570 
2571   if (!mysql)
2572   {
2573     /* Error is already set in mysql_detatch_stmt_list */
2574     DBUG_RETURN(1);
2575   }
2576 
2577   if (reset_stmt_handle(stmt, RESET_STORE_RESULT | RESET_CLEAR_ERROR))
2578     DBUG_RETURN(1);
2579   /*
2580     No need to check for stmt->state: if the statement wasn't
2581     prepared we'll get 'unknown statement handler' error from server.
2582   */
2583   if (mysql->methods->stmt_execute(stmt))
2584     DBUG_RETURN(1);
2585   stmt->state= MYSQL_STMT_EXECUTE_DONE;
2586   if (mysql->field_count)
2587   {
2588     reinit_result_set_metadata(stmt);
2589     prepare_to_fetch_result(stmt);
2590   }
2591   DBUG_RETURN(MY_TEST(stmt->last_errno));
2592 }
2593 
2594 
2595 /*
2596   Return total parameters count in the statement
2597 */
2598 
2599 ulong STDCALL mysql_stmt_param_count(MYSQL_STMT * stmt)
2600 {
2601   DBUG_ENTER("mysql_stmt_param_count");
2602   DBUG_RETURN(stmt->param_count);
2603 }
2604 
2605 /*
2606   Return total affected rows from the last statement
2607 */
2608 
2609 my_ulonglong STDCALL mysql_stmt_affected_rows(MYSQL_STMT *stmt)
2610 {
2611   return stmt->affected_rows;
2612 }
2613 
2614 
2615 /*
2616   Returns the number of result columns for the most recent query
2617   run on this statement.
2618 */
2619 
2620 unsigned int STDCALL mysql_stmt_field_count(MYSQL_STMT *stmt)
2621 {
2622   return stmt->field_count;
2623 }
2624 
2625 /*
2626   Return last inserted id for auto_increment columns.
2627 
2628   SYNOPSIS
2629     mysql_stmt_insert_id()
2630     stmt    statement handle
2631 
2632   DESCRIPTION
2633     Current implementation of this call has a caveat: stmt->insert_id is
2634     unconditionally updated from mysql->insert_id in the end of each
2635     mysql_stmt_execute(). This works OK if mysql->insert_id contains new
2636     value (sent in reply to mysql_stmt_execute()), otherwise stmt->insert_id
2637     value gets undefined, as it's updated from some arbitrary value saved in
2638     connection structure during some other call.
2639 */
2640 
2641 my_ulonglong STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt)
2642 {
2643   return stmt->insert_id;
2644 }
2645 
2646 
2647 static my_bool int_is_null_true= 1;		/* Used for MYSQL_TYPE_NULL */
2648 static my_bool int_is_null_false= 0;
2649 
2650 
2651 /*
2652   Set up input data buffers for a statement.
2653 
2654   SYNOPSIS
2655     mysql_stmt_bind_param()
2656     stmt    statement handle
2657             The statement must be prepared with mysql_stmt_prepare().
2658     my_bind Array of mysql_stmt_param_count() bind parameters.
2659             This function doesn't check that size of this argument
2660             is >= mysql_stmt_field_count(): it's user's responsibility.
2661 
2662   DESCRIPTION
2663     Use this call after mysql_stmt_prepare() to bind user variables to
2664     placeholders.
2665     Each element of bind array stands for a placeholder. Placeholders
2666     are counted from 0.  For example statement
2667     'INSERT INTO t (a, b) VALUES (?, ?)'
2668     contains two placeholders, and for such statement you should supply
2669     bind array of two elements (MYSQL_BIND bind[2]).
2670 
2671     By properly initializing bind array you can bind virtually any
2672     C language type to statement's placeholders:
2673     First, it's strongly recommended to always zero-initialize entire
2674     bind structure before setting its members. This will both shorten
2675     your application code and make it robust to future extensions of
2676     MYSQL_BIND structure.
2677     Then you need to assign typecode of your application buffer to
2678     MYSQL_BIND::buffer_type. The following typecodes with their
2679     correspondence to C language types are supported:
2680     MYSQL_TYPE_TINY       for 8-bit integer variables. Normally it's
2681                           'signed char' and 'unsigned char';
2682     MYSQL_TYPE_SHORT      for 16-bit signed and unsigned variables. This
2683                           is usually 'short' and 'unsigned short';
2684     MYSQL_TYPE_LONG       for 32-bit signed and unsigned variables. It
2685                           corresponds to 'int' and 'unsigned int' on
2686                           vast majority of platforms. On IA-32 and some
2687                           other 32-bit systems you can also use 'long'
2688                           here;
2689     MYSQL_TYPE_LONGLONG   64-bit signed or unsigned integer.  Stands for
2690                           '[unsigned] long long' on most platforms;
2691     MYSQL_TYPE_FLOAT      32-bit floating point type, 'float' on most
2692                           systems;
2693     MYSQL_TYPE_DOUBLE     64-bit floating point type, 'double' on most
2694                           systems;
2695     MYSQL_TYPE_TIME       broken-down time stored in MYSQL_TIME
2696                           structure
2697     MYSQL_TYPE_DATE       date stored in MYSQL_TIME structure
2698     MYSQL_TYPE_DATETIME   datetime stored in MYSQL_TIME structure See
2699                           more on how to use these types for sending
2700                           dates and times below;
2701     MYSQL_TYPE_STRING     character string, assumed to be in
2702                           character-set-client. If character set of
2703                           client is not equal to character set of
2704                           column, value for this placeholder will be
2705                           converted to destination character set before
2706                           insert.
2707     MYSQL_TYPE_BLOB       sequence of bytes. This sequence is assumed to
2708                           be in binary character set (which is the same
2709                           as no particular character set), and is never
2710                           converted to any other character set. See also
2711                           notes about supplying string/blob length
2712                           below.
2713     MYSQL_TYPE_NULL       special typecode for binding nulls.
2714     These C/C++ types are not supported yet by the API: long double,
2715     bool.
2716 
2717     As you can see from the list above, it's responsibility of
2718     application programmer to ensure that chosen typecode properly
2719     corresponds to host language type. For example on all platforms
2720     where we build MySQL packages (as of MySQL 4.1.4) int is a 32-bit
2721     type. So for int you can always assume that proper typecode is
2722     MYSQL_TYPE_LONG (however queer it sounds, the name is legacy of the
2723     old MySQL API). In contrary sizeof(long) can be 4 or 8 8-bit bytes,
2724     depending on platform.
2725 
2726     TODO: provide client typedefs for each integer and floating point
2727     typecode, i. e. int8, uint8, float32, etc.
2728 
2729     Once typecode was set, it's necessary to assign MYSQL_BIND::buffer
2730     to point to the buffer of given type. Finally, additional actions
2731     may be taken for some types or use cases:
2732 
2733     Binding integer types.
2734       For integer types you might also need to set MYSQL_BIND::is_unsigned
2735       member. Set it to TRUE when binding unsigned char, unsigned short,
2736       unsigned int, unsigned long, unsigned long long.
2737 
2738     Binding floating point types.
2739       For floating point types you just need to set
2740       MYSQL_BIND::buffer_type and MYSQL_BIND::buffer. The rest of the
2741       members should be zero-initialized.
2742 
2743     Binding NULLs.
2744       You might have a column always NULL, never NULL, or sometimes
2745       NULL.  For an always NULL column set MYSQL_BIND::buffer_type to
2746       MYSQL_TYPE_NULL.  The rest of the members just need to be
2747       zero-initialized.  For never NULL columns set
2748       MYSQL_BIND::is_null to 0, or this has already been done if you
2749       zero-initialized the entire structure.  If you set
2750       MYSQL_TYPE::is_null to point to an application buffer of type
2751       'my_bool', then this buffer will be checked on each execution:
2752       this way you can set the buffer to TRUE, or any non-0 value for
2753       NULLs, and to FALSE or 0 for not NULL data.
2754 
2755     Binding text strings and sequences of bytes.
2756       For strings, in addition to MYSQL_BIND::buffer_type and
2757       MYSQL_BIND::buffer you need to set MYSQL_BIND::length or
2758       MYSQL_BIND::buffer_length.  If 'length' is set, 'buffer_length'
2759       is ignored. 'buffer_length' member should be used when size of
2760       string doesn't change between executions. If you want to vary
2761       buffer length for each value, set 'length' to point to an
2762       application buffer of type 'unsigned long' and set this long to
2763       length of the string before each mysql_stmt_execute().
2764 
2765     Binding dates and times.
2766       For binding dates and times prepared statements API provides
2767       clients with MYSQL_TIME structure. A pointer to instance of this
2768       structure should be assigned to MYSQL_BIND::buffer whenever
2769       MYSQL_TYPE_TIME, MYSQL_TYPE_DATE, MYSQL_TYPE_DATETIME typecodes
2770       are used.  When typecode is MYSQL_TYPE_TIME, only members
2771       'hour', 'minute', 'second' and 'neg' (is time offset negative)
2772       are used. These members only will be sent to the server.
2773       MYSQL_TYPE_DATE implies use of 'year', 'month', 'day', 'neg'.
2774       MYSQL_TYPE_DATETIME utilizes both parts of MYSQL_TIME structure.
2775       You don't have to set MYSQL_TIME::time_type member: it's not
2776       used when sending data to the server, typecode information is
2777       enough.  'second_part' member can hold microsecond precision of
2778       time value, but now it's only supported on protocol level: you
2779       can't store microsecond in a column, or use in temporal
2780       calculations. However, if you send a time value with microsecond
2781       part for 'SELECT ?', statement, you'll get it back unchanged
2782       from the server.
2783 
2784     Data conversion.
2785       If conversion from host language type to data representation,
2786       corresponding to SQL type, is required it's done on the server.
2787       Data truncation is possible when conversion is lossy. For
2788       example, if you supply MYSQL_TYPE_DATETIME value out of valid
2789       SQL type TIMESTAMP range, the same conversion will be applied as
2790       if this value would have been sent as string in the old
2791       protocol.  TODO: document how the server will behave in case of
2792       truncation/data loss.
2793 
2794     After variables were bound, you can repeatedly set/change their
2795     values and mysql_stmt_execute() the statement.
2796 
2797     See also: mysql_stmt_send_long_data() for sending long text/blob
2798     data in pieces, examples in tests/mysql_client_test.c.
2799     Next steps you might want to make:
2800     - execute statement with mysql_stmt_execute(),
2801     - reset statement using mysql_stmt_reset() or reprepare it with
2802       another query using mysql_stmt_prepare()
2803     - close statement with mysql_stmt_close().
2804 
2805   IMPLEMENTATION
2806     The function copies given bind array to internal storage of the
2807     statement, and sets up typecode-specific handlers to perform
2808     serialization of bound data. This means that although you don't need
2809     to call this routine after each assignment to bind buffers, you
2810     need to call it each time you change parameter typecodes, or other
2811     members of MYSQL_BIND array.
2812     This is a pure local call. Data types of client buffers are sent
2813     along with buffers' data at first execution of the statement.
2814 
2815   RETURN
2816     0  success
2817     1  error, can be retrieved with mysql_stmt_error.
2818 */
2819 
2820 my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *my_bind)
2821 {
2822   uint count=0;
2823   MYSQL_BIND *param, *end;
2824   DBUG_ENTER("mysql_stmt_bind_param");
2825 
2826   if (!stmt->param_count)
2827   {
2828     if ((int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE)
2829     {
2830       set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate, NULL);
2831       DBUG_RETURN(1);
2832     }
2833     DBUG_RETURN(0);
2834   }
2835 
2836   /* Allocated on prepare */
2837   memcpy((char*) stmt->params, (char*) my_bind,
2838 	 sizeof(MYSQL_BIND) * stmt->param_count);
2839 
2840   for (param= stmt->params, end= param+stmt->param_count;
2841        param < end ;
2842        param++)
2843   {
2844     param->param_number= count++;
2845     param->long_data_used= 0;
2846 
2847     /* If param->is_null is not set, then the value can never be NULL */
2848     if (!param->is_null)
2849       param->is_null= &int_is_null_false;
2850 
2851     /* Setup data copy functions for the different supported types */
2852     switch (param->buffer_type) {
2853     case MYSQL_TYPE_NULL:
2854       param->is_null= &int_is_null_true;
2855       break;
2856     case MYSQL_TYPE_TINY:
2857       /* Force param->length as this is fixed for this type */
2858       param->length= &param->buffer_length;
2859       param->buffer_length= 1;
2860       param->store_param_func= store_param_tinyint;
2861       break;
2862     case MYSQL_TYPE_SHORT:
2863       param->length= &param->buffer_length;
2864       param->buffer_length= 2;
2865       param->store_param_func= store_param_short;
2866       break;
2867     case MYSQL_TYPE_LONG:
2868       param->length= &param->buffer_length;
2869       param->buffer_length= 4;
2870       param->store_param_func= store_param_int32;
2871       break;
2872     case MYSQL_TYPE_LONGLONG:
2873       param->length= &param->buffer_length;
2874       param->buffer_length= 8;
2875       param->store_param_func= store_param_int64;
2876       break;
2877     case MYSQL_TYPE_FLOAT:
2878       param->length= &param->buffer_length;
2879       param->buffer_length= 4;
2880       param->store_param_func= store_param_float;
2881       break;
2882     case MYSQL_TYPE_DOUBLE:
2883       param->length= &param->buffer_length;
2884       param->buffer_length= 8;
2885       param->store_param_func= store_param_double;
2886       break;
2887     case MYSQL_TYPE_TIME:
2888       param->store_param_func= store_param_time;
2889       param->buffer_length= MAX_TIME_REP_LENGTH;
2890       break;
2891     case MYSQL_TYPE_DATE:
2892       param->store_param_func= store_param_date;
2893       param->buffer_length= MAX_DATE_REP_LENGTH;
2894       break;
2895     case MYSQL_TYPE_DATETIME:
2896     case MYSQL_TYPE_TIMESTAMP:
2897       param->store_param_func= store_param_datetime;
2898       param->buffer_length= MAX_DATETIME_REP_LENGTH;
2899       break;
2900     case MYSQL_TYPE_TINY_BLOB:
2901     case MYSQL_TYPE_MEDIUM_BLOB:
2902     case MYSQL_TYPE_LONG_BLOB:
2903     case MYSQL_TYPE_BLOB:
2904     case MYSQL_TYPE_VARCHAR:
2905     case MYSQL_TYPE_VAR_STRING:
2906     case MYSQL_TYPE_STRING:
2907     case MYSQL_TYPE_DECIMAL:
2908     case MYSQL_TYPE_NEWDECIMAL:
2909       param->store_param_func= store_param_str;
2910       /*
2911         For variable length types user must set either length or
2912         buffer_length.
2913       */
2914       break;
2915     default:
2916       strmov(stmt->sqlstate, unknown_sqlstate);
2917       sprintf(stmt->last_error,
2918 	      ER(stmt->last_errno= CR_UNSUPPORTED_PARAM_TYPE),
2919 	      param->buffer_type, count);
2920       DBUG_RETURN(1);
2921     }
2922     /*
2923       If param->length is not given, change it to point to buffer_length.
2924       This way we can always use *param->length to get the length of data
2925     */
2926     if (!param->length)
2927       param->length= &param->buffer_length;
2928   }
2929   /* We have to send/resend type information to MySQL */
2930   stmt->send_types_to_server= TRUE;
2931   stmt->bind_param_done= TRUE;
2932   DBUG_RETURN(0);
2933 }
2934 
2935 
2936 /********************************************************************
2937  Long data implementation
2938 *********************************************************************/
2939 
2940 /*
2941   Send long data in pieces to the server
2942 
2943   SYNOPSIS
2944     mysql_stmt_send_long_data()
2945     stmt			Statement handler
2946     param_number		Parameter number (0 - N-1)
2947     data			Data to send to server
2948     length			Length of data to send (may be 0)
2949 
2950   DESCRIPTION
2951     This call can be used repeatedly to send long data in pieces
2952     for any string/binary placeholder. Data supplied for
2953     a placeholder is saved at server side till execute, and then
2954     used instead of value from MYSQL_BIND object. More precisely,
2955     if long data for a parameter was supplied, MYSQL_BIND object
2956     corresponding to this parameter is not sent to server. In the
2957     end of execution long data states of placeholders are reset,
2958     so next time values of such placeholders will be taken again
2959     from MYSQL_BIND array.
2960     The server does not reply to this call: if there was an error
2961     in data handling (which now only can happen if server run out
2962     of memory) it would be returned in reply to
2963     mysql_stmt_execute().
2964     You should choose type of long data carefully if you care
2965     about character set conversions performed by server when the
2966     statement is executed.  No conversion is performed at all for
2967     MYSQL_TYPE_BLOB and other binary typecodes. For
2968     MYSQL_TYPE_STRING and the rest of text placeholders data is
2969     converted from client character set to character set of
2970     connection. If these character sets are different, this
2971     conversion may require additional memory at server, equal to
2972     total size of supplied pieces.
2973 
2974   RETURN VALUES
2975     0	ok
2976     1	error
2977 */
2978 
2979 my_bool STDCALL
2980 mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number,
2981 		     const char *data, ulong length)
2982 {
2983   MYSQL_BIND *param;
2984   DBUG_ENTER("mysql_stmt_send_long_data");
2985   DBUG_ASSERT(stmt != 0);
2986   DBUG_PRINT("enter",("param no: %d  data: %p, length : %ld",
2987 		      param_number, data, length));
2988 
2989   /*
2990     We only need to check for stmt->param_count, if it's not null
2991     prepare was done.
2992   */
2993   if (param_number >= stmt->param_count)
2994   {
2995     set_stmt_error(stmt, CR_INVALID_PARAMETER_NO, unknown_sqlstate, NULL);
2996     DBUG_RETURN(1);
2997   }
2998 
2999   param= stmt->params+param_number;
3000   if (!IS_LONGDATA(param->buffer_type))
3001   {
3002     /* Long data handling should be used only for string/binary types */
3003     strmov(stmt->sqlstate, unknown_sqlstate);
3004     sprintf(stmt->last_error, ER(stmt->last_errno= CR_INVALID_BUFFER_USE),
3005 	    param->param_number);
3006     DBUG_RETURN(1);
3007   }
3008 
3009   /*
3010     Send long data packet if there is data or we're sending long data
3011     for the first time.
3012   */
3013   if (length || param->long_data_used == 0)
3014   {
3015     MYSQL *mysql= stmt->mysql;
3016     /* Packet header: stmt id (4 bytes), param no (2 bytes) */
3017     uchar buff[MYSQL_LONG_DATA_HEADER];
3018 
3019     int4store(buff, stmt->stmt_id);
3020     int2store(buff + 4, param_number);
3021     param->long_data_used= 1;
3022 
3023     /*
3024       Note that we don't get any ok packet from the server in this case
3025       This is intentional to save bandwidth.
3026     */
3027     if ((*mysql->methods->advanced_command)(mysql, COM_STMT_SEND_LONG_DATA,
3028                                             buff, sizeof(buff), (uchar*) data,
3029                                             length, 1, stmt))
3030     {
3031       /*
3032         Don't set stmt error if stmt->mysql is NULL, as the error in this case
3033         has already been set by mysql_prune_stmt_list().
3034       */
3035       if (stmt->mysql)
3036         set_stmt_errmsg(stmt, &mysql->net);
3037       DBUG_RETURN(1);
3038     }
3039   }
3040   DBUG_RETURN(0);
3041 }
3042 
3043 
3044 /********************************************************************
3045  Fetch and conversion of result set rows (binary protocol).
3046 *********************************************************************/
3047 
3048 /*
3049   Read date, (time, datetime) value from network buffer and store it
3050   in MYSQL_TIME structure.
3051 
3052   SYNOPSIS
3053     read_binary_{date,time,datetime}()
3054     tm    MYSQL_TIME structure to fill
3055     pos   pointer to current position in network buffer.
3056           These functions increase pos to point to the beginning of the
3057           next column.
3058 
3059   Auxiliary functions to read time (date, datetime) values from network
3060   buffer and store in MYSQL_TIME structure. Jointly used by conversion
3061   and no-conversion fetching.
3062 */
3063 
3064 static void read_binary_time(MYSQL_TIME *tm, uchar **pos)
3065 {
3066   /* net_field_length will set pos to the first byte of data */
3067   uint length= net_field_length(pos);
3068 
3069   if (length)
3070   {
3071     uchar *to= *pos;
3072     tm->neg=    to[0];
3073 
3074     tm->day=    (ulong) sint4korr(to+1);
3075     tm->hour=   (uint) to[5];
3076     tm->minute= (uint) to[6];
3077     tm->second= (uint) to[7];
3078     tm->second_part= (length > 8) ? (ulong) sint4korr(to+8) : 0;
3079     tm->year= tm->month= 0;
3080     if (tm->day)
3081     {
3082       /* Convert days to hours at once */
3083       tm->hour+= tm->day*24;
3084       tm->day= 0;
3085     }
3086     tm->time_type= MYSQL_TIMESTAMP_TIME;
3087 
3088     *pos+= length;
3089   }
3090   else
3091     set_zero_time(tm, MYSQL_TIMESTAMP_TIME);
3092 }
3093 
3094 static void read_binary_datetime(MYSQL_TIME *tm, uchar **pos)
3095 {
3096   uint length= net_field_length(pos);
3097 
3098   if (length)
3099   {
3100     uchar *to= *pos;
3101 
3102     tm->neg=    0;
3103     tm->year=   (uint) sint2korr(to);
3104     tm->month=  (uint) to[2];
3105     tm->day=    (uint) to[3];
3106 
3107     if (length > 4)
3108     {
3109       tm->hour=   (uint) to[4];
3110       tm->minute= (uint) to[5];
3111       tm->second= (uint) to[6];
3112     }
3113     else
3114       tm->hour= tm->minute= tm->second= 0;
3115     tm->second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0;
3116     tm->time_type= MYSQL_TIMESTAMP_DATETIME;
3117 
3118     *pos+= length;
3119   }
3120   else
3121     set_zero_time(tm, MYSQL_TIMESTAMP_DATETIME);
3122 }
3123 
3124 static void read_binary_date(MYSQL_TIME *tm, uchar **pos)
3125 {
3126   uint length= net_field_length(pos);
3127 
3128   if (length)
3129   {
3130     uchar *to= *pos;
3131     tm->year =  (uint) sint2korr(to);
3132     tm->month=  (uint) to[2];
3133     tm->day= (uint) to[3];
3134 
3135     tm->hour= tm->minute= tm->second= 0;
3136     tm->second_part= 0;
3137     tm->neg= 0;
3138     tm->time_type= MYSQL_TIMESTAMP_DATE;
3139 
3140     *pos+= length;
3141   }
3142   else
3143     set_zero_time(tm, MYSQL_TIMESTAMP_DATE);
3144 }
3145 
3146 
3147 /*
3148   Convert string to supplied buffer of any type.
3149 
3150   SYNOPSIS
3151     fetch_string_with_conversion()
3152     param   output buffer descriptor
3153     value   column data
3154     length  data length
3155 */
3156 
3157 static void fetch_string_with_conversion(MYSQL_BIND *param, char *value, size_t length)
3158 {
3159   char *buffer= (char *)param->buffer;
3160   int err= 0;
3161   char *endptr= value + length;
3162 
3163   /*
3164     This function should support all target buffer types: the rest
3165     of conversion functions can delegate conversion to it.
3166   */
3167   switch (param->buffer_type) {
3168   case MYSQL_TYPE_NULL: /* do nothing */
3169     break;
3170   case MYSQL_TYPE_TINY:
3171   {
3172     longlong data= my_strtoll10(value, &endptr, &err);
3173     *param->error= (IS_TRUNCATED(data, param->is_unsigned,
3174                                  INT_MIN8, INT_MAX8, UINT_MAX8) || err > 0);
3175     *buffer= (uchar) data;
3176     break;
3177   }
3178   case MYSQL_TYPE_SHORT:
3179   {
3180     longlong data= my_strtoll10(value, &endptr, &err);
3181     *param->error= (IS_TRUNCATED(data, param->is_unsigned,
3182                                  INT_MIN16, INT_MAX16, UINT_MAX16) || err > 0);
3183     shortstore(buffer, (short) data);
3184     break;
3185   }
3186   case MYSQL_TYPE_LONG:
3187   {
3188     longlong data= my_strtoll10(value, &endptr, &err);
3189     *param->error= (IS_TRUNCATED(data, param->is_unsigned,
3190                                  INT_MIN32, INT_MAX32, UINT_MAX32) || err > 0);
3191     longstore(buffer, (int32) data);
3192     break;
3193   }
3194   case MYSQL_TYPE_LONGLONG:
3195   {
3196     longlong data= my_strtoll10(value, &endptr, &err);
3197     *param->error= param->is_unsigned ? err != 0 :
3198                                        (err > 0 || (err == 0 && data < 0));
3199     longlongstore(buffer, data);
3200     break;
3201   }
3202   case MYSQL_TYPE_FLOAT:
3203   {
3204     double data= my_strntod(&my_charset_latin1, value, length, &endptr, &err);
3205     float fdata= (float) data;
3206     *param->error= (fdata != data) | MY_TEST(err);
3207     floatstore(buffer, fdata);
3208     break;
3209   }
3210   case MYSQL_TYPE_DOUBLE:
3211   {
3212     double data= my_strntod(&my_charset_latin1, value, length, &endptr, &err);
3213     *param->error= MY_TEST(err);
3214     doublestore(buffer, data);
3215     break;
3216   }
3217   case MYSQL_TYPE_TIME:
3218   {
3219     MYSQL_TIME *tm= (MYSQL_TIME *)buffer;
3220     MYSQL_TIME_STATUS status;
3221     str_to_datetime_or_date_or_time(value, length, tm, 0, &status,
3222                                     TIME_MAX_HOUR, UINT_MAX32);
3223     err= status.warnings;
3224     *param->error= MY_TEST(err);
3225     break;
3226   }
3227   case MYSQL_TYPE_DATE:
3228   case MYSQL_TYPE_DATETIME:
3229   case MYSQL_TYPE_TIMESTAMP:
3230   {
3231     MYSQL_TIME *tm= (MYSQL_TIME *)buffer;
3232     MYSQL_TIME_STATUS status;
3233     (void) str_to_datetime_or_date(value, length, tm, 0, &status);
3234     err= status.warnings;
3235     *param->error= MY_TEST(err) && (param->buffer_type == MYSQL_TYPE_DATE &&
3236                                     tm->time_type != MYSQL_TIMESTAMP_DATE);
3237     break;
3238   }
3239   case MYSQL_TYPE_TINY_BLOB:
3240   case MYSQL_TYPE_MEDIUM_BLOB:
3241   case MYSQL_TYPE_LONG_BLOB:
3242   case MYSQL_TYPE_BLOB:
3243   case MYSQL_TYPE_DECIMAL:
3244   case MYSQL_TYPE_NEWDECIMAL:
3245   default:
3246   {
3247     /*
3248       Copy column data to the buffer taking into account offset,
3249       data length and buffer length.
3250     */
3251     char *start= value + param->offset;
3252     char *end= value + length;
3253     ulong copy_length;
3254     if (start < end)
3255     {
3256       copy_length= (ulong)(end - start);
3257       /* We've got some data beyond offset: copy up to buffer_length bytes */
3258       if (param->buffer_length)
3259         memcpy(buffer, start, MY_MIN(copy_length, param->buffer_length));
3260     }
3261     else
3262       copy_length= 0;
3263     if (copy_length < param->buffer_length)
3264       buffer[copy_length]= '\0';
3265     *param->error= copy_length > param->buffer_length;
3266     /*
3267       param->length will always contain length of entire column;
3268       number of copied bytes may be way different:
3269     */
3270     *param->length= (ulong)length;
3271     break;
3272   }
3273   }
3274 }
3275 
3276 
3277 /*
3278   Convert integer value to client buffer of any type.
3279 
3280   SYNOPSIS
3281     fetch_long_with_conversion()
3282     param   output buffer descriptor
3283     field   column metadata
3284     value   column data
3285 */
3286 
3287 static void fetch_long_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
3288                                        longlong value, my_bool is_unsigned)
3289 {
3290   char *buffer= (char *)param->buffer;
3291 
3292   switch (param->buffer_type) {
3293   case MYSQL_TYPE_NULL: /* do nothing */
3294     break;
3295   case MYSQL_TYPE_TINY:
3296     *param->error= IS_TRUNCATED(value, param->is_unsigned,
3297                                 INT_MIN8, INT_MAX8, UINT_MAX8);
3298     *(uchar *)param->buffer= (uchar) value;
3299     break;
3300   case MYSQL_TYPE_SHORT:
3301     *param->error= IS_TRUNCATED(value, param->is_unsigned,
3302                                 INT_MIN16, INT_MAX16, UINT_MAX16);
3303     shortstore(buffer, (short) value);
3304     break;
3305   case MYSQL_TYPE_LONG:
3306     *param->error= IS_TRUNCATED(value, param->is_unsigned,
3307                                 INT_MIN32, INT_MAX32, UINT_MAX32);
3308     longstore(buffer, (int32) value);
3309     break;
3310   case MYSQL_TYPE_LONGLONG:
3311     longlongstore(buffer, value);
3312     *param->error= param->is_unsigned != is_unsigned && value < 0;
3313     break;
3314   case MYSQL_TYPE_FLOAT:
3315   {
3316     /*
3317       We need to mark the local variable volatile to
3318       workaround Intel FPU executive precision feature.
3319       (See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 for details)
3320     */
3321     volatile float data;
3322     if (is_unsigned)
3323     {
3324       data= (float) ulonglong2double(value);
3325       *param->error= ((ulonglong) value) != ((ulonglong) data);
3326     }
3327     else
3328     {
3329       data= (float)value;
3330       *param->error= value != ((longlong) data);
3331     }
3332     floatstore(buffer, data);
3333     break;
3334   }
3335   case MYSQL_TYPE_DOUBLE:
3336   {
3337     volatile double data;
3338     if (is_unsigned)
3339     {
3340       data= ulonglong2double(value);
3341       *param->error= ((ulonglong) value) != ((ulonglong) data);
3342     }
3343     else
3344     {
3345       data= (double)value;
3346       *param->error= value != ((longlong) data);
3347     }
3348     doublestore(buffer, data);
3349     break;
3350   }
3351   case MYSQL_TYPE_TIME:
3352   case MYSQL_TYPE_DATE:
3353   case MYSQL_TYPE_TIMESTAMP:
3354   case MYSQL_TYPE_DATETIME:
3355   {
3356     int error;
3357     value= number_to_datetime_or_date(value, 0, (MYSQL_TIME *) buffer, 0, &error);
3358     *param->error= MY_TEST(error);
3359     break;
3360   }
3361   default:
3362   {
3363     uchar buff[22];                              /* Enough for longlong */
3364     uchar *end= (uchar*) longlong10_to_str(value, (char*) buff,
3365                                            is_unsigned ? 10: -10);
3366     /* Resort to string conversion which supports all typecodes */
3367     uint length= (uint) (end-buff);
3368 
3369     if (field->flags & ZEROFILL_FLAG && length < field->length &&
3370         field->length < 21)
3371     {
3372       bmove_upp(buff+field->length,buff+length, length);
3373       bfill(buff, field->length - length,'0');
3374       length= field->length;
3375     }
3376     fetch_string_with_conversion(param, (char*) buff, length);
3377     break;
3378   }
3379   }
3380 }
3381 
3382 /*
3383   Convert double/float column to supplied buffer of any type.
3384 
3385   SYNOPSIS
3386     fetch_float_with_conversion()
3387     param   output buffer descriptor
3388     field   column metadata
3389     value   column data
3390     type    either MY_GCVT_ARG_FLOAT or MY_GCVT_ARG_DOUBLE.
3391             Affects the maximum number of significant digits
3392             returned by my_gcvt().
3393 */
3394 
3395 static void fetch_float_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
3396                                         double value, my_gcvt_arg_type type)
3397 {
3398   char *buffer= (char *)param->buffer;
3399   double val64 = (value < 0 ? -floor(-value) : floor(value));
3400 
3401   switch (param->buffer_type) {
3402   case MYSQL_TYPE_NULL: /* do nothing */
3403     break;
3404   case MYSQL_TYPE_TINY:
3405     /*
3406       We need to _store_ data in the buffer before the truncation check to
3407       workaround Intel FPU executive precision feature.
3408       (See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 for details)
3409       Sic: AFAIU it does not guarantee to work.
3410     */
3411     if (param->is_unsigned)
3412       *buffer= (uint8) value;
3413     else
3414       *buffer= (int8) value;
3415     *param->error= val64 != (param->is_unsigned ? (double)((uint8) *buffer) :
3416                                                   (double)((int8) *buffer));
3417     break;
3418   case MYSQL_TYPE_SHORT:
3419     if (param->is_unsigned)
3420     {
3421       ushort data= (ushort) value;
3422       shortstore(buffer, data);
3423     }
3424     else
3425     {
3426       short data= (short) value;
3427       shortstore(buffer, data);
3428     }
3429     *param->error= val64 != (param->is_unsigned ? (double) (*(ushort*) buffer):
3430                                                   (double) (*(short*) buffer));
3431     break;
3432   case MYSQL_TYPE_LONG:
3433     if (param->is_unsigned)
3434     {
3435       uint32 data= (uint32) value;
3436       longstore(buffer, data);
3437     }
3438     else
3439     {
3440       int32 data= (int32) value;
3441       longstore(buffer, data);
3442     }
3443     *param->error= val64 != (param->is_unsigned ? (double) (*(uint32*) buffer):
3444                                                   (double) (*(int32*) buffer));
3445       break;
3446   case MYSQL_TYPE_LONGLONG:
3447     if (param->is_unsigned)
3448     {
3449       ulonglong data= (ulonglong) value;
3450       longlongstore(buffer, data);
3451     }
3452     else
3453     {
3454       longlong data= (longlong) value;
3455       longlongstore(buffer, data);
3456     }
3457     *param->error= val64 != (param->is_unsigned ?
3458                              ulonglong2double(*(ulonglong*) buffer) :
3459                              (double) (*(longlong*) buffer));
3460     break;
3461   case MYSQL_TYPE_FLOAT:
3462   {
3463     float data= (float) value;
3464     floatstore(buffer, data);
3465     *param->error= (*(float*) buffer) != value;
3466     break;
3467   }
3468   case MYSQL_TYPE_DOUBLE:
3469   {
3470     doublestore(buffer, value);
3471     break;
3472   }
3473   default:
3474   {
3475     /*
3476       Resort to fetch_string_with_conversion: this should handle
3477       floating point -> string conversion nicely, honor all typecodes
3478       and param->offset possibly set in mysql_stmt_fetch_column
3479     */
3480     char buff[FLOATING_POINT_BUFFER];
3481     size_t len;
3482     if (field->decimals >= FLOATING_POINT_DECIMALS)
3483       len= my_gcvt(value, type,
3484                    (int) MY_MIN(sizeof(buff)-1, param->buffer_length),
3485                    buff, NULL);
3486     else
3487       len= my_fcvt(value, (int) field->decimals, buff, NULL);
3488 
3489     if (field->flags & ZEROFILL_FLAG && len < field->length &&
3490         field->length < MAX_DOUBLE_STRING_REP_LENGTH - 1)
3491     {
3492       bmove_upp((uchar*) buff + field->length, (uchar*) buff + len,
3493                 len);
3494       bfill((char*) buff, field->length - len, '0');
3495       len= field->length;
3496     }
3497     fetch_string_with_conversion(param, buff, len);
3498 
3499     break;
3500   }
3501   }
3502 }
3503 
3504 
3505 /*
3506   Fetch time/date/datetime to supplied buffer of any type
3507 
3508   SYNOPSIS
3509     param   output buffer descriptor
3510     time    column data
3511 */
3512 
3513 static void fetch_datetime_with_conversion(MYSQL_BIND *param,
3514                                            MYSQL_FIELD *field,
3515                                            MYSQL_TIME *my_time)
3516 {
3517   switch (param->buffer_type) {
3518   case MYSQL_TYPE_NULL: /* do nothing */
3519     break;
3520   case MYSQL_TYPE_DATE:
3521     *(MYSQL_TIME *)(param->buffer)= *my_time;
3522     *param->error= my_time->time_type != MYSQL_TIMESTAMP_DATE;
3523     break;
3524   case MYSQL_TYPE_TIME:
3525     *(MYSQL_TIME *)(param->buffer)= *my_time;
3526     *param->error= my_time->time_type != MYSQL_TIMESTAMP_TIME;
3527     break;
3528   case MYSQL_TYPE_DATETIME:
3529   case MYSQL_TYPE_TIMESTAMP:
3530     *(MYSQL_TIME *)(param->buffer)= *my_time;
3531     /* No error: time and date are compatible with datetime */
3532     break;
3533   case MYSQL_TYPE_YEAR:
3534     shortstore(param->buffer, my_time->year);
3535     *param->error= 1;
3536     break;
3537   case MYSQL_TYPE_FLOAT:
3538   case MYSQL_TYPE_DOUBLE:
3539   {
3540     ulonglong value= TIME_to_ulonglong(my_time);
3541     fetch_float_with_conversion(param, field,
3542                                 ulonglong2double(value), MY_GCVT_ARG_DOUBLE);
3543     break;
3544   }
3545   case MYSQL_TYPE_TINY:
3546   case MYSQL_TYPE_SHORT:
3547   case MYSQL_TYPE_INT24:
3548   case MYSQL_TYPE_LONG:
3549   case MYSQL_TYPE_LONGLONG:
3550   {
3551     longlong value= (longlong) TIME_to_ulonglong(my_time);
3552     fetch_long_with_conversion(param, field, value, TRUE);
3553     break;
3554   }
3555   default:
3556   {
3557     /*
3558       Convert time value  to string and delegate the rest to
3559       fetch_string_with_conversion:
3560     */
3561     char buff[MAX_DATE_STRING_REP_LENGTH];
3562     uint length= my_TIME_to_str(my_time, buff, field->decimals);
3563     /* Resort to string conversion */
3564     fetch_string_with_conversion(param, (char *)buff, length);
3565     break;
3566   }
3567   }
3568 }
3569 
3570 
3571 /*
3572   Fetch and convert result set column to output buffer.
3573 
3574   SYNOPSIS
3575     fetch_result_with_conversion()
3576     param   output buffer descriptor
3577     field   column metadata
3578     row     points to a column of result set tuple in binary format
3579 
3580   DESCRIPTION
3581     This is a fallback implementation of column fetch used
3582     if column and output buffer types do not match.
3583     Increases tuple pointer to point at the next column within the
3584     tuple.
3585 */
3586 
3587 static void fetch_result_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
3588                                          uchar **row)
3589 {
3590   enum enum_field_types field_type= field->type;
3591   uint field_is_unsigned= field->flags & UNSIGNED_FLAG;
3592 
3593   switch (field_type) {
3594   case MYSQL_TYPE_TINY:
3595   {
3596     uchar value= **row;
3597     /* sic: we need to cast to 'signed char' as 'char' may be unsigned */
3598     longlong data= field_is_unsigned ? (longlong) value :
3599                                        (longlong) (signed char) value;
3600     fetch_long_with_conversion(param, field, data, 0);
3601     *row+= 1;
3602     break;
3603   }
3604   case MYSQL_TYPE_SHORT:
3605   case MYSQL_TYPE_YEAR:
3606   {
3607     short value= sint2korr(*row);
3608     longlong data= field_is_unsigned ? (longlong) (unsigned short) value :
3609                                        (longlong) value;
3610     fetch_long_with_conversion(param, field, data, 0);
3611     *row+= 2;
3612     break;
3613   }
3614   case MYSQL_TYPE_INT24: /* mediumint is sent as 4 bytes int */
3615   case MYSQL_TYPE_LONG:
3616   {
3617     int32 value= sint4korr(*row);
3618     longlong data= field_is_unsigned ? (longlong) (uint32) value :
3619                                        (longlong) value;
3620     fetch_long_with_conversion(param, field, data, 0);
3621     *row+= 4;
3622     break;
3623   }
3624   case MYSQL_TYPE_LONGLONG:
3625   {
3626     longlong value= (longlong)sint8korr(*row);
3627     fetch_long_with_conversion(param, field, value,
3628                                field->flags & UNSIGNED_FLAG);
3629     *row+= 8;
3630     break;
3631   }
3632   case MYSQL_TYPE_FLOAT:
3633   {
3634     float value;
3635     float4get(value,*row);
3636     fetch_float_with_conversion(param, field, value, MY_GCVT_ARG_FLOAT);
3637     *row+= 4;
3638     break;
3639   }
3640   case MYSQL_TYPE_DOUBLE:
3641   {
3642     double value;
3643     float8get(value,*row);
3644     fetch_float_with_conversion(param, field, value, MY_GCVT_ARG_DOUBLE);
3645     *row+= 8;
3646     break;
3647   }
3648   case MYSQL_TYPE_DATE:
3649   {
3650     MYSQL_TIME tm;
3651 
3652     read_binary_date(&tm, row);
3653     fetch_datetime_with_conversion(param, field, &tm);
3654     break;
3655   }
3656   case MYSQL_TYPE_TIME:
3657   {
3658     MYSQL_TIME tm;
3659 
3660     read_binary_time(&tm, row);
3661     fetch_datetime_with_conversion(param, field, &tm);
3662     break;
3663   }
3664   case MYSQL_TYPE_DATETIME:
3665   case MYSQL_TYPE_TIMESTAMP:
3666   {
3667     MYSQL_TIME tm;
3668 
3669     read_binary_datetime(&tm, row);
3670     fetch_datetime_with_conversion(param, field, &tm);
3671     break;
3672   }
3673   default:
3674   {
3675     ulong length= net_field_length(row);
3676     fetch_string_with_conversion(param, (char*) *row, length);
3677     *row+= length;
3678     break;
3679   }
3680   }
3681 }
3682 
3683 
3684 /*
3685   Functions to fetch data to application buffers without conversion.
3686 
3687   All functions have the following characteristics:
3688 
3689   SYNOPSIS
3690     fetch_result_xxx()
3691     param   MySQL bind param
3692     pos     Row value
3693 
3694   DESCRIPTION
3695     These are no-conversion functions, used in binary protocol to store
3696     rows in application buffers. A function used only if type of binary data
3697     is compatible with type of application buffer.
3698 
3699   RETURN
3700     none
3701 */
3702 
3703 static void fetch_result_tinyint(MYSQL_BIND *param, MYSQL_FIELD *field,
3704                                  uchar **row)
3705 {
3706   my_bool field_is_unsigned= MY_TEST(field->flags & UNSIGNED_FLAG);
3707   uchar data= **row;
3708   *(uchar *)param->buffer= data;
3709   *param->error= param->is_unsigned != field_is_unsigned && data > INT_MAX8;
3710   (*row)++;
3711 }
3712 
3713 static void fetch_result_short(MYSQL_BIND *param, MYSQL_FIELD *field,
3714                                uchar **row)
3715 {
3716   my_bool field_is_unsigned= MY_TEST(field->flags & UNSIGNED_FLAG);
3717   ushort data= (ushort) sint2korr(*row);
3718   shortstore(param->buffer, data);
3719   *param->error= param->is_unsigned != field_is_unsigned && data > INT_MAX16;
3720   *row+= 2;
3721 }
3722 
3723 static void fetch_result_int32(MYSQL_BIND *param,
3724                                MYSQL_FIELD *field __attribute__((unused)),
3725                                uchar **row)
3726 {
3727   my_bool field_is_unsigned= MY_TEST(field->flags & UNSIGNED_FLAG);
3728   uint32 data= (uint32) sint4korr(*row);
3729   longstore(param->buffer, data);
3730   *param->error= param->is_unsigned != field_is_unsigned && data > INT_MAX32;
3731   *row+= 4;
3732 }
3733 
3734 static void fetch_result_int64(MYSQL_BIND *param,
3735                                MYSQL_FIELD *field __attribute__((unused)),
3736                                uchar **row)
3737 {
3738   my_bool field_is_unsigned= MY_TEST(field->flags & UNSIGNED_FLAG);
3739   ulonglong data= (ulonglong) sint8korr(*row);
3740   *param->error= param->is_unsigned != field_is_unsigned && data > LONGLONG_MAX;
3741   longlongstore(param->buffer, data);
3742   *row+= 8;
3743 }
3744 
3745 static void fetch_result_float(MYSQL_BIND *param,
3746                                MYSQL_FIELD *field __attribute__((unused)),
3747                                uchar **row)
3748 {
3749   float value;
3750   float4get(value,*row);
3751   floatstore(param->buffer, value);
3752   *row+= 4;
3753 }
3754 
3755 static void fetch_result_double(MYSQL_BIND *param,
3756                                 MYSQL_FIELD *field __attribute__((unused)),
3757                                 uchar **row)
3758 {
3759   double value;
3760   float8get(value,*row);
3761   doublestore(param->buffer, value);
3762   *row+= 8;
3763 }
3764 
3765 static void fetch_result_time(MYSQL_BIND *param,
3766                               MYSQL_FIELD *field __attribute__((unused)),
3767                               uchar **row)
3768 {
3769   MYSQL_TIME *tm= (MYSQL_TIME *)param->buffer;
3770   read_binary_time(tm, row);
3771 }
3772 
3773 static void fetch_result_date(MYSQL_BIND *param,
3774                               MYSQL_FIELD *field __attribute__((unused)),
3775                               uchar **row)
3776 {
3777   MYSQL_TIME *tm= (MYSQL_TIME *)param->buffer;
3778   read_binary_date(tm, row);
3779 }
3780 
3781 static void fetch_result_datetime(MYSQL_BIND *param,
3782                                   MYSQL_FIELD *field __attribute__((unused)),
3783                                   uchar **row)
3784 {
3785   MYSQL_TIME *tm= (MYSQL_TIME *)param->buffer;
3786   read_binary_datetime(tm, row);
3787 }
3788 
3789 static void fetch_result_bin(MYSQL_BIND *param,
3790                              MYSQL_FIELD *field __attribute__((unused)),
3791                              uchar **row)
3792 {
3793   ulong length= net_field_length(row);
3794   ulong copy_length= MY_MIN(length, param->buffer_length);
3795   memcpy(param->buffer, (char *)*row, copy_length);
3796   *param->length= length;
3797   *param->error= copy_length < length;
3798   *row+= length;
3799 }
3800 
3801 static void fetch_result_str(MYSQL_BIND *param,
3802                              MYSQL_FIELD *field __attribute__((unused)),
3803                              uchar **row)
3804 {
3805   ulong length= net_field_length(row);
3806   ulong copy_length= MY_MIN(length, param->buffer_length);
3807   memcpy(param->buffer, (char *)*row, copy_length);
3808   /* Add an end null if there is room in the buffer */
3809   if (copy_length != param->buffer_length)
3810     ((uchar *)param->buffer)[copy_length]= '\0';
3811   *param->length= length;			/* return total length */
3812   *param->error= copy_length < length;
3813   *row+= length;
3814 }
3815 
3816 
3817 /*
3818   functions to calculate max lengths for strings during
3819   mysql_stmt_store_result()
3820 */
3821 
3822 static void skip_result_fixed(MYSQL_BIND *param,
3823 			      MYSQL_FIELD *field __attribute__((unused)),
3824 			      uchar **row)
3825 
3826 {
3827   (*row)+= param->pack_length;
3828 }
3829 
3830 
3831 static void skip_result_with_length(MYSQL_BIND *param __attribute__((unused)),
3832 				    MYSQL_FIELD *field __attribute__((unused)),
3833 				    uchar **row)
3834 
3835 {
3836   ulong length= net_field_length(row);
3837   (*row)+= length;
3838 }
3839 
3840 
3841 static void skip_result_string(MYSQL_BIND *param __attribute__((unused)),
3842 			       MYSQL_FIELD *field,
3843 			       uchar **row)
3844 
3845 {
3846   ulong length= net_field_length(row);
3847   (*row)+= length;
3848   if (field->max_length < length)
3849     field->max_length= length;
3850 }
3851 
3852 
3853 /*
3854   Check that two field types are binary compatible i. e.
3855   have equal representation in the binary protocol and
3856   require client-side buffers of the same type.
3857 
3858   SYNOPSIS
3859     is_binary_compatible()
3860     type1   parameter type supplied by user
3861     type2   field type, obtained from result set metadata
3862 
3863   RETURN
3864     TRUE or FALSE
3865 */
3866 
3867 static my_bool is_binary_compatible(enum enum_field_types type1,
3868                                     enum enum_field_types type2)
3869 {
3870   static const enum enum_field_types
3871     range1[]= { MYSQL_TYPE_SHORT, MYSQL_TYPE_YEAR, MYSQL_TYPE_NULL },
3872     range2[]= { MYSQL_TYPE_INT24, MYSQL_TYPE_LONG, MYSQL_TYPE_NULL },
3873     range3[]= { MYSQL_TYPE_DATETIME, MYSQL_TYPE_TIMESTAMP, MYSQL_TYPE_NULL },
3874     range4[]= { MYSQL_TYPE_ENUM, MYSQL_TYPE_SET, MYSQL_TYPE_TINY_BLOB,
3875                 MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB, MYSQL_TYPE_BLOB,
3876                 MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_STRING, MYSQL_TYPE_GEOMETRY,
3877                 MYSQL_TYPE_DECIMAL, MYSQL_TYPE_NULL };
3878   static const enum enum_field_types
3879    *range_list[]= { range1, range2, range3, range4 },
3880    **range_list_end= range_list + sizeof(range_list)/sizeof(*range_list);
3881    const enum enum_field_types **range, *type;
3882 
3883   if (type1 == type2)
3884     return TRUE;
3885   for (range= range_list; range != range_list_end; ++range)
3886   {
3887     /* check that both type1 and type2 are in the same range */
3888     my_bool type1_found= FALSE, type2_found= FALSE;
3889     for (type= *range; *type != MYSQL_TYPE_NULL; type++)
3890     {
3891       type1_found|= type1 == *type;
3892       type2_found|= type2 == *type;
3893     }
3894     if (type1_found || type2_found)
3895       return type1_found && type2_found;
3896   }
3897   return FALSE;
3898 }
3899 
3900 
3901 /*
3902   Setup a fetch function for one column of a result set.
3903 
3904   SYNOPSIS
3905     setup_one_fetch_function()
3906     param    output buffer descriptor
3907     field    column descriptor
3908 
3909   DESCRIPTION
3910     When user binds result set buffers or when result set
3911     metadata is changed, we need to setup fetch (and possibly
3912     conversion) functions for all columns of the result set.
3913     In addition to that here we set up skip_result function, used
3914     to update result set metadata in case when
3915     STMT_ATTR_UPDATE_MAX_LENGTH attribute is set.
3916     Notice that while fetch_result is chosen depending on both
3917     field->type and param->type, skip_result depends on field->type
3918     only.
3919 
3920   RETURN
3921     TRUE   fetch function for this typecode was not found (typecode
3922           is not supported by the client library)
3923     FALSE  success
3924 */
3925 
3926 static my_bool setup_one_fetch_function(MYSQL_BIND *param, MYSQL_FIELD *field)
3927 {
3928   my_bool field_is_unsigned;
3929   DBUG_ENTER("setup_one_fetch_function");
3930 
3931   /* Setup data copy functions for the different supported types */
3932   switch (param->buffer_type) {
3933   case MYSQL_TYPE_NULL: /* for dummy binds */
3934     /*
3935       It's not binary compatible with anything the server can return:
3936       no need to setup fetch_result, as it'll be reset anyway
3937     */
3938     *param->length= 0;
3939     break;
3940   case MYSQL_TYPE_TINY:
3941     param->fetch_result= fetch_result_tinyint;
3942     *param->length= 1;
3943     break;
3944   case MYSQL_TYPE_SHORT:
3945   case MYSQL_TYPE_YEAR:
3946     param->fetch_result= fetch_result_short;
3947     *param->length= 2;
3948     break;
3949   case MYSQL_TYPE_INT24:
3950   case MYSQL_TYPE_LONG:
3951     param->fetch_result= fetch_result_int32;
3952     *param->length= 4;
3953     break;
3954   case MYSQL_TYPE_LONGLONG:
3955     param->fetch_result= fetch_result_int64;
3956     *param->length= 8;
3957     break;
3958   case MYSQL_TYPE_FLOAT:
3959     param->fetch_result= fetch_result_float;
3960     *param->length= 4;
3961     break;
3962   case MYSQL_TYPE_DOUBLE:
3963     param->fetch_result= fetch_result_double;
3964     *param->length= 8;
3965     break;
3966   case MYSQL_TYPE_TIME:
3967     param->fetch_result= fetch_result_time;
3968     *param->length= sizeof(MYSQL_TIME);
3969     break;
3970   case MYSQL_TYPE_DATE:
3971     param->fetch_result= fetch_result_date;
3972     *param->length= sizeof(MYSQL_TIME);
3973     break;
3974   case MYSQL_TYPE_DATETIME:
3975   case MYSQL_TYPE_TIMESTAMP:
3976     param->fetch_result= fetch_result_datetime;
3977     *param->length= sizeof(MYSQL_TIME);
3978     break;
3979   case MYSQL_TYPE_TINY_BLOB:
3980   case MYSQL_TYPE_MEDIUM_BLOB:
3981   case MYSQL_TYPE_LONG_BLOB:
3982   case MYSQL_TYPE_BLOB:
3983   case MYSQL_TYPE_BIT:
3984     DBUG_ASSERT(param->buffer_length != 0);
3985     param->fetch_result= fetch_result_bin;
3986     break;
3987   case MYSQL_TYPE_VAR_STRING:
3988   case MYSQL_TYPE_STRING:
3989   case MYSQL_TYPE_DECIMAL:
3990   case MYSQL_TYPE_NEWDECIMAL:
3991   case MYSQL_TYPE_NEWDATE:
3992     DBUG_ASSERT(param->buffer_length != 0);
3993     param->fetch_result= fetch_result_str;
3994     break;
3995   default:
3996     DBUG_PRINT("error", ("Unknown param->buffer_type: %u",
3997                          (uint) param->buffer_type));
3998     DBUG_RETURN(TRUE);
3999   }
4000   if (! is_binary_compatible(param->buffer_type, field->type))
4001     param->fetch_result= fetch_result_with_conversion;
4002 
4003   /* Setup skip_result functions (to calculate max_length) */
4004   param->skip_result= skip_result_fixed;
4005   field_is_unsigned= MY_TEST(field->flags & UNSIGNED_FLAG);
4006   switch (field->type) {
4007   case MYSQL_TYPE_NULL: /* for dummy binds */
4008     param->pack_length= 0;
4009     field->max_length= 0;
4010     break;
4011   case MYSQL_TYPE_TINY:
4012     param->pack_length= 1;
4013     field->max_length= field_is_unsigned ? 3 : 4; /* '255' and '-127' */
4014     break;
4015   case MYSQL_TYPE_YEAR:
4016   case MYSQL_TYPE_SHORT:
4017     param->pack_length= 2;
4018     field->max_length= field_is_unsigned ? 5 : 6; /* 65536 and '-32767' */
4019     break;
4020   case MYSQL_TYPE_INT24:
4021     field->max_length=  8;  /* '16777216' or in '-8388607' */
4022     param->pack_length= 4;
4023     break;
4024   case MYSQL_TYPE_LONG:
4025     field->max_length= field_is_unsigned ? 10 : 11; /* '4294967295' and '-2147483647' */
4026     param->pack_length= 4;
4027     break;
4028   case MYSQL_TYPE_LONGLONG:
4029     field->max_length= 20; /* '18446744073709551616' or -9223372036854775808 */
4030     param->pack_length= 8;
4031     break;
4032   case MYSQL_TYPE_FLOAT:
4033     param->pack_length= 4;
4034     field->max_length= MAX_DOUBLE_STRING_REP_LENGTH;
4035     break;
4036   case MYSQL_TYPE_DOUBLE:
4037     param->pack_length= 8;
4038     field->max_length= MAX_DOUBLE_STRING_REP_LENGTH;
4039     break;
4040   case MYSQL_TYPE_TIME:
4041     field->max_length= 17;                    /* -819:23:48.123456 */
4042     param->skip_result= skip_result_with_length;
4043     break;
4044   case MYSQL_TYPE_DATE:
4045     field->max_length= 10;                    /* 2003-11-11 */
4046     param->skip_result= skip_result_with_length;
4047     break;
4048   case MYSQL_TYPE_DATETIME:
4049   case MYSQL_TYPE_TIMESTAMP:
4050     param->skip_result= skip_result_with_length;
4051     field->max_length= MAX_DATE_STRING_REP_LENGTH;
4052     break;
4053   case MYSQL_TYPE_DECIMAL:
4054   case MYSQL_TYPE_NEWDECIMAL:
4055   case MYSQL_TYPE_ENUM:
4056   case MYSQL_TYPE_SET:
4057   case MYSQL_TYPE_GEOMETRY:
4058   case MYSQL_TYPE_TINY_BLOB:
4059   case MYSQL_TYPE_MEDIUM_BLOB:
4060   case MYSQL_TYPE_LONG_BLOB:
4061   case MYSQL_TYPE_BLOB:
4062   case MYSQL_TYPE_VAR_STRING:
4063   case MYSQL_TYPE_STRING:
4064   case MYSQL_TYPE_BIT:
4065   case MYSQL_TYPE_NEWDATE:
4066     param->skip_result= skip_result_string;
4067     break;
4068   default:
4069     DBUG_PRINT("error", ("Unknown field->type: %u", (uint) field->type));
4070     DBUG_RETURN(TRUE);
4071   }
4072   DBUG_RETURN(FALSE);
4073 }
4074 
4075 
4076 /*
4077   Setup the bind buffers for resultset processing
4078 */
4079 
4080 my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *my_bind)
4081 {
4082   MYSQL_BIND *param, *end;
4083   MYSQL_FIELD *field;
4084   ulong       bind_count= stmt->field_count;
4085   uint        param_count= 0;
4086   DBUG_ENTER("mysql_stmt_bind_result");
4087   DBUG_PRINT("enter",("field_count: %lu", bind_count));
4088 
4089   if (!bind_count)
4090   {
4091     int errorcode= (int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE ?
4092                    CR_NO_PREPARE_STMT : CR_NO_STMT_METADATA;
4093     set_stmt_error(stmt, errorcode, unknown_sqlstate, NULL);
4094     DBUG_RETURN(1);
4095   }
4096 
4097   /*
4098     We only need to check that stmt->field_count - if it is not null
4099     stmt->bind was initialized in mysql_stmt_prepare
4100     stmt->bind overlaps with bind if mysql_stmt_bind_param
4101     is called from mysql_stmt_store_result.
4102   */
4103 
4104   if (stmt->bind != my_bind)
4105     memcpy((char*) stmt->bind, (char*) my_bind,
4106            sizeof(MYSQL_BIND) * bind_count);
4107 
4108   for (param= stmt->bind, end= param + bind_count, field= stmt->fields ;
4109        param < end ;
4110        param++, field++)
4111   {
4112     DBUG_PRINT("info",("buffer_type: %u  field_type: %u",
4113                        (uint) param->buffer_type, (uint) field->type));
4114     /*
4115       Set param->is_null to point to a dummy variable if it's not set.
4116       This is to make the execute code easier
4117     */
4118     if (!param->is_null)
4119       param->is_null= &param->is_null_value;
4120 
4121     if (!param->length)
4122       param->length= &param->length_value;
4123 
4124     if (!param->error)
4125       param->error= &param->error_value;
4126 
4127     param->param_number= param_count++;
4128     param->offset= 0;
4129 
4130     if (setup_one_fetch_function(param, field))
4131     {
4132       strmov(stmt->sqlstate, unknown_sqlstate);
4133       sprintf(stmt->last_error,
4134               ER(stmt->last_errno= CR_UNSUPPORTED_PARAM_TYPE),
4135               field->type, param_count);
4136       DBUG_RETURN(1);
4137     }
4138   }
4139   stmt->bind_result_done= BIND_RESULT_DONE;
4140   if (stmt->mysql->options.report_data_truncation)
4141     stmt->bind_result_done|= REPORT_DATA_TRUNCATION;
4142 
4143   DBUG_RETURN(0);
4144 }
4145 
4146 
4147 /*
4148   Fetch row data to bind buffers
4149 */
4150 
4151 static int stmt_fetch_row(MYSQL_STMT *stmt, uchar *row)
4152 {
4153   MYSQL_BIND  *my_bind, *end;
4154   MYSQL_FIELD *field;
4155   uchar *null_ptr, bit;
4156   int truncation_count= 0;
4157   /*
4158     Precondition: if stmt->field_count is zero or row is NULL, read_row_*
4159     function must return no data.
4160   */
4161   DBUG_ASSERT(stmt->field_count);
4162   DBUG_ASSERT(row);
4163 
4164   if (!stmt->bind_result_done)
4165   {
4166     /* If output parameters were not bound we should just return success */
4167     return 0;
4168   }
4169 
4170   null_ptr= row;
4171   row+= (stmt->field_count+9)/8;		/* skip null bits */
4172   bit= 4;					/* first 2 bits are reserved */
4173 
4174   /* Copy complete row to application buffers */
4175   for (my_bind= stmt->bind, end= my_bind + stmt->field_count,
4176          field= stmt->fields ;
4177        my_bind < end ;
4178        my_bind++, field++)
4179   {
4180     *my_bind->error= 0;
4181     if (*null_ptr & bit)
4182     {
4183       /*
4184         We should set both row_ptr and is_null to be able to see
4185         nulls in mysql_stmt_fetch_column. This is because is_null may point
4186         to user data which can be overwritten between mysql_stmt_fetch and
4187         mysql_stmt_fetch_column, and in this case nullness of column will be
4188         lost. See mysql_stmt_fetch_column for details.
4189       */
4190       my_bind->row_ptr= NULL;
4191       *my_bind->is_null= 1;
4192     }
4193     else
4194     {
4195       *my_bind->is_null= 0;
4196       my_bind->row_ptr= row;
4197       (*my_bind->fetch_result)(my_bind, field, &row);
4198       truncation_count+= *my_bind->error;
4199     }
4200     if (!((bit<<=1) & 255))
4201     {
4202       bit= 1;					/* To next uchar */
4203       null_ptr++;
4204     }
4205   }
4206   if (truncation_count && (stmt->bind_result_done & REPORT_DATA_TRUNCATION))
4207     return MYSQL_DATA_TRUNCATED;
4208   return 0;
4209 }
4210 
4211 
4212 int cli_unbuffered_fetch(MYSQL *mysql, char **row)
4213 {
4214   if (packet_error == cli_safe_read(mysql))
4215     return 1;
4216 
4217   *row= ((mysql->net.read_pos[0] == 254) ? NULL :
4218 	 (char*) (mysql->net.read_pos+1));
4219   return 0;
4220 }
4221 
4222 
4223 /*
4224   Fetch and return row data to bound buffers, if any
4225 */
4226 
4227 int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt)
4228 {
4229   int rc;
4230   uchar *row;
4231   DBUG_ENTER("mysql_stmt_fetch");
4232 
4233   if ((rc= (*stmt->read_row_func)(stmt, &row)) ||
4234       ((rc= stmt_fetch_row(stmt, row)) && rc != MYSQL_DATA_TRUNCATED))
4235   {
4236     stmt->state= MYSQL_STMT_PREPARE_DONE;       /* XXX: this is buggy */
4237     stmt->read_row_func= (rc == MYSQL_NO_DATA) ?
4238       stmt_read_row_no_data : stmt_read_row_no_result_set;
4239   }
4240   else
4241   {
4242     /* This is to know in mysql_stmt_fetch_column that data was fetched */
4243     stmt->state= MYSQL_STMT_FETCH_DONE;
4244   }
4245   DBUG_RETURN(rc);
4246 }
4247 
4248 
4249 /*
4250   Fetch data for one specified column data
4251 
4252   SYNOPSIS
4253     mysql_stmt_fetch_column()
4254     stmt		Prepared statement handler
4255     my_bind		Where data should be placed. Should be filled in as
4256 			when calling mysql_stmt_bind_result()
4257     column		Column to fetch (first column is 0)
4258     ulong offset	Offset in result data (to fetch blob in pieces)
4259 			This is normally 0
4260   RETURN
4261     0	ok
4262     1	error
4263 */
4264 
4265 int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *my_bind,
4266                                     uint column, ulong offset)
4267 {
4268   MYSQL_BIND *param= stmt->bind+column;
4269   DBUG_ENTER("mysql_stmt_fetch_column");
4270 
4271   if ((int) stmt->state < (int) MYSQL_STMT_FETCH_DONE)
4272   {
4273     set_stmt_error(stmt, CR_NO_DATA, unknown_sqlstate, NULL);
4274     DBUG_RETURN(1);
4275   }
4276   if (column >= stmt->field_count)
4277   {
4278     set_stmt_error(stmt, CR_INVALID_PARAMETER_NO, unknown_sqlstate, NULL);
4279     DBUG_RETURN(1);
4280   }
4281 
4282   if (!my_bind->error)
4283     my_bind->error= &my_bind->error_value;
4284   *my_bind->error= 0;
4285   if (param->row_ptr)
4286   {
4287     MYSQL_FIELD *field= stmt->fields+column;
4288     uchar *row= param->row_ptr;
4289     my_bind->offset= offset;
4290     if (my_bind->is_null)
4291       *my_bind->is_null= 0;
4292     if (my_bind->length) /* Set the length if non char/binary types */
4293       *my_bind->length= *param->length;
4294     else
4295       my_bind->length= &param->length_value;       /* Needed for fetch_result() */
4296     fetch_result_with_conversion(my_bind, field, &row);
4297   }
4298   else
4299   {
4300     if (my_bind->is_null)
4301       *my_bind->is_null= 1;
4302   }
4303   DBUG_RETURN(0);
4304 }
4305 
4306 
4307 /*
4308   Read all rows of data from server  (binary format)
4309 */
4310 
4311 int cli_read_binary_rows(MYSQL_STMT *stmt)
4312 {
4313   ulong      pkt_len;
4314   uchar      *cp;
4315   MYSQL      *mysql= stmt->mysql;
4316   MYSQL_DATA *result= &stmt->result;
4317   MYSQL_ROWS *cur, **prev_ptr= &result->data;
4318   NET        *net;
4319 
4320   DBUG_ENTER("cli_read_binary_rows");
4321 
4322   if (!mysql)
4323   {
4324     set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL);
4325     DBUG_RETURN(1);
4326   }
4327 
4328   net = &mysql->net;
4329 
4330   while ((pkt_len= cli_safe_read(mysql)) != packet_error)
4331   {
4332     cp= net->read_pos;
4333     if (cp[0] != 254 || pkt_len >= 8)
4334     {
4335       if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc,
4336                                           sizeof(MYSQL_ROWS) + pkt_len - 1)))
4337       {
4338         set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL);
4339         goto err;
4340       }
4341       cur->data= (MYSQL_ROW) (cur+1);
4342       *prev_ptr= cur;
4343       prev_ptr= &cur->next;
4344       memcpy((char *) cur->data, (char *) cp+1, pkt_len-1);
4345       cur->length= pkt_len;		/* To allow us to do sanity checks */
4346       result->rows++;
4347     }
4348     else
4349     {
4350       /* end of data */
4351       *prev_ptr= 0;
4352       mysql->warning_count= uint2korr(cp+1);
4353       mysql->server_status= uint2korr(cp+3);
4354       DBUG_PRINT("info",("status: %u  warning_count: %u",
4355                          mysql->server_status, mysql->warning_count));
4356       DBUG_RETURN(0);
4357     }
4358   }
4359   set_stmt_errmsg(stmt, net);
4360 
4361 err:
4362   DBUG_RETURN(1);
4363 }
4364 
4365 
4366 /*
4367   Update meta data for statement
4368 
4369   SYNOPSIS
4370     stmt_update_metadata()
4371     stmt			Statement handler
4372     row				Binary data
4373 
4374   NOTES
4375     Only updates MYSQL_FIELD->max_length for strings
4376 */
4377 
4378 static void stmt_update_metadata(MYSQL_STMT *stmt, MYSQL_ROWS *data)
4379 {
4380   MYSQL_BIND  *my_bind, *end;
4381   MYSQL_FIELD *field;
4382   uchar *null_ptr, bit;
4383   uchar *row= (uchar*) data->data;
4384 #ifdef DBUG_ASSERT_EXISTS
4385   uchar *row_end= row + data->length;
4386 #endif
4387 
4388   null_ptr= row;
4389   row+= (stmt->field_count+9)/8;		/* skip null bits */
4390   bit= 4;					/* first 2 bits are reserved */
4391 
4392   /* Go through all fields and calculate metadata */
4393   for (my_bind= stmt->bind, end= my_bind + stmt->field_count, field= stmt->fields ;
4394        my_bind < end ;
4395        my_bind++, field++)
4396   {
4397     if (!(*null_ptr & bit))
4398       (*my_bind->skip_result)(my_bind, field, &row);
4399     DBUG_ASSERT(row <= row_end);
4400     if (!((bit<<=1) & 255))
4401     {
4402       bit= 1;					/* To next uchar */
4403       null_ptr++;
4404     }
4405   }
4406 }
4407 
4408 
4409 /*
4410   Store or buffer the binary results to stmt
4411 */
4412 
4413 int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
4414 {
4415   MYSQL *mysql= stmt->mysql;
4416   MYSQL_DATA *result= &stmt->result;
4417   DBUG_ENTER("mysql_stmt_store_result");
4418 
4419   if (!mysql)
4420   {
4421     /* mysql can be reset in mysql_close called from mysql_reconnect */
4422     set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL);
4423     DBUG_RETURN(1);
4424   }
4425 
4426   if (!stmt->field_count)
4427     DBUG_RETURN(0);
4428 
4429   if ((int) stmt->state < (int) MYSQL_STMT_EXECUTE_DONE)
4430   {
4431     set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, NULL);
4432     DBUG_RETURN(1);
4433   }
4434 
4435   if (stmt->last_errno)
4436   {
4437     /* An attempt to use an invalid statement handle. */
4438     DBUG_RETURN(1);
4439   }
4440 
4441   if (mysql->status == MYSQL_STATUS_READY &&
4442       stmt->server_status & SERVER_STATUS_CURSOR_EXISTS)
4443   {
4444     /*
4445       Server side cursor exist, tell server to start sending the rows
4446     */
4447     NET *net= &mysql->net;
4448     uchar buff[4 /* statement id */ +
4449                4 /* number of rows to fetch */];
4450 
4451     /* Send row request to the server */
4452     int4store(buff, stmt->stmt_id);
4453     int4store(buff + 4, (int)~0); /* number of rows to fetch */
4454     if (cli_advanced_command(mysql, COM_STMT_FETCH, buff, sizeof(buff),
4455                              (uchar*) 0, 0, 1, stmt))
4456     {
4457       /*
4458         Don't set stmt error if stmt->mysql is NULL, as the error in this case
4459         has already been set by mysql_prune_stmt_list().
4460       */
4461       if (stmt->mysql)
4462         set_stmt_errmsg(stmt, net);
4463       DBUG_RETURN(1);
4464     }
4465   }
4466   else if (mysql->status != MYSQL_STATUS_STATEMENT_GET_RESULT)
4467   {
4468     set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, NULL);
4469     DBUG_RETURN(1);
4470   }
4471 
4472   if (stmt->update_max_length && !stmt->bind_result_done)
4473   {
4474     /*
4475       We must initialize the bind structure to be able to calculate
4476       max_length
4477     */
4478     MYSQL_BIND  *my_bind, *end;
4479     MYSQL_FIELD *field;
4480     bzero((char*) stmt->bind, sizeof(*stmt->bind)* stmt->field_count);
4481 
4482     for (my_bind= stmt->bind, end= my_bind + stmt->field_count,
4483            field= stmt->fields;
4484 	 my_bind < end ;
4485 	 my_bind++, field++)
4486     {
4487       my_bind->buffer_type= MYSQL_TYPE_NULL;
4488       my_bind->buffer_length=1;
4489     }
4490 
4491     if (mysql_stmt_bind_result(stmt, stmt->bind))
4492       DBUG_RETURN(1);
4493     stmt->bind_result_done= 0;			/* No normal bind done */
4494   }
4495 
4496   if ((*mysql->methods->read_binary_rows)(stmt))
4497   {
4498     free_root(&result->alloc, MYF(MY_KEEP_PREALLOC));
4499     result->data= NULL;
4500     result->rows= 0;
4501     mysql->status= MYSQL_STATUS_READY;
4502     DBUG_RETURN(1);
4503   }
4504 
4505   /* Assert that if there was a cursor, all rows have been fetched */
4506   DBUG_ASSERT(mysql->status != MYSQL_STATUS_READY ||
4507               (mysql->server_status & SERVER_STATUS_LAST_ROW_SENT));
4508 
4509   if (stmt->update_max_length)
4510   {
4511     MYSQL_ROWS *cur= result->data;
4512     for(; cur; cur=cur->next)
4513       stmt_update_metadata(stmt, cur);
4514   }
4515 
4516   stmt->data_cursor= result->data;
4517   mysql->affected_rows= stmt->affected_rows= result->rows;
4518   stmt->read_row_func= stmt_read_row_buffered;
4519   mysql->unbuffered_fetch_owner= 0;             /* set in stmt_execute */
4520   mysql->status= MYSQL_STATUS_READY;		/* server is ready */
4521   DBUG_RETURN(0); /* Data buffered, must be fetched with mysql_stmt_fetch() */
4522 }
4523 
4524 
4525 /*
4526   Seek to desired row in the statement result set
4527 */
4528 
4529 MYSQL_ROW_OFFSET STDCALL
4530 mysql_stmt_row_seek(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET row)
4531 {
4532   MYSQL_ROW_OFFSET offset= stmt->data_cursor;
4533   DBUG_ENTER("mysql_stmt_row_seek");
4534 
4535   stmt->data_cursor= row;
4536   DBUG_RETURN(offset);
4537 }
4538 
4539 
4540 /*
4541   Return the current statement row cursor position
4542 */
4543 
4544 MYSQL_ROW_OFFSET STDCALL
4545 mysql_stmt_row_tell(MYSQL_STMT *stmt)
4546 {
4547   DBUG_ENTER("mysql_stmt_row_tell");
4548 
4549   DBUG_RETURN(stmt->data_cursor);
4550 }
4551 
4552 
4553 /*
4554   Move the stmt result set data cursor to specified row
4555 */
4556 
4557 void STDCALL
4558 mysql_stmt_data_seek(MYSQL_STMT *stmt, my_ulonglong row)
4559 {
4560   MYSQL_ROWS *tmp= stmt->result.data;
4561   DBUG_ENTER("mysql_stmt_data_seek");
4562   DBUG_PRINT("enter",("row id to seek: %ld",(long) row));
4563 
4564   for (; tmp && row; --row, tmp= tmp->next)
4565     ;
4566   stmt->data_cursor= tmp;
4567   if (!row && tmp)
4568   {
4569        /*  Rewind the counter */
4570     stmt->read_row_func= stmt_read_row_buffered;
4571     stmt->state= MYSQL_STMT_EXECUTE_DONE;
4572   }
4573   DBUG_VOID_RETURN;
4574 }
4575 
4576 
4577 /*
4578   Return total rows the current statement result set
4579 */
4580 
4581 my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt)
4582 {
4583   DBUG_ENTER("mysql_stmt_num_rows");
4584 
4585   DBUG_RETURN(stmt->result.rows);
4586 }
4587 
4588 
4589 /*
4590   Free the client side memory buffers, reset long data state
4591   on client if necessary, and reset the server side statement if
4592   this has been requested.
4593 */
4594 
4595 static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags)
4596 {
4597   /* If statement hasn't been prepared there is nothing to reset */
4598   if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE)
4599   {
4600     MYSQL *mysql= stmt->mysql;
4601     MYSQL_DATA *result= &stmt->result;
4602 
4603     /*
4604       Reset stored result set if so was requested or it's a part
4605       of cursor fetch.
4606     */
4607     if (flags & RESET_STORE_RESULT)
4608     {
4609       /* Result buffered */
4610       free_root(&result->alloc, MYF(MY_KEEP_PREALLOC));
4611       result->data= NULL;
4612       result->rows= 0;
4613       stmt->data_cursor= NULL;
4614     }
4615     if (flags & RESET_LONG_DATA)
4616     {
4617       MYSQL_BIND *param= stmt->params, *param_end= param + stmt->param_count;
4618       /* Clear long_data_used flags */
4619       for (; param < param_end; param++)
4620         param->long_data_used= 0;
4621     }
4622     stmt->read_row_func= stmt_read_row_no_result_set;
4623     if (mysql)
4624     {
4625       if ((int) stmt->state > (int) MYSQL_STMT_PREPARE_DONE)
4626       {
4627         if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled)
4628           mysql->unbuffered_fetch_owner= 0;
4629         if (stmt->field_count && mysql->status != MYSQL_STATUS_READY)
4630         {
4631           /* There is a result set and it belongs to this statement */
4632           (*mysql->methods->flush_use_result)(mysql, FALSE);
4633           if (mysql->unbuffered_fetch_owner)
4634             *mysql->unbuffered_fetch_owner= TRUE;
4635           mysql->status= MYSQL_STATUS_READY;
4636         }
4637         if (flags & RESET_ALL_BUFFERS)
4638         {
4639           /* mysql_stmt_next_result will flush all pending
4640              result sets
4641           */
4642           while (mysql_more_results(mysql) &&
4643                  mysql_stmt_next_result(stmt) == 0);
4644         }
4645       }
4646       if (flags & RESET_SERVER_SIDE)
4647       {
4648         /*
4649           Reset the server side statement and close the server side
4650           cursor if it exists.
4651         */
4652         uchar buff[MYSQL_STMT_HEADER]; /* packet header: 4 bytes for stmt id */
4653         int4store(buff, stmt->stmt_id);
4654         if ((*mysql->methods->advanced_command)(mysql, COM_STMT_RESET, buff,
4655                                                 sizeof(buff), 0, 0, 0, stmt))
4656         {
4657           set_stmt_errmsg(stmt, &mysql->net);
4658           stmt->state= MYSQL_STMT_INIT_DONE;
4659           return 1;
4660         }
4661       }
4662     }
4663     if (flags & RESET_CLEAR_ERROR)
4664       stmt_clear_error(stmt);
4665     stmt->state= MYSQL_STMT_PREPARE_DONE;
4666   }
4667   return 0;
4668 }
4669 
4670 my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt)
4671 {
4672   DBUG_ENTER("mysql_stmt_free_result");
4673 
4674   /* Free the client side and close the server side cursor if there is one */
4675   DBUG_RETURN(reset_stmt_handle(stmt, RESET_LONG_DATA | RESET_STORE_RESULT |
4676                                 RESET_CLEAR_ERROR));
4677 }
4678 
4679 /********************************************************************
4680  statement error handling and close
4681 *********************************************************************/
4682 
4683 /*
4684   Close the statement handle by freeing all alloced resources
4685 
4686   SYNOPSIS
4687     mysql_stmt_close()
4688     stmt	       Statement handle
4689 
4690   RETURN VALUES
4691     0	ok
4692     1	error
4693 */
4694 
4695 my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
4696 {
4697   MYSQL *mysql= stmt->mysql;
4698   int rc= 0;
4699   DBUG_ENTER("mysql_stmt_close");
4700 
4701   free_root(&stmt->result.alloc, MYF(0));
4702   free_root(&stmt->mem_root, MYF(0));
4703   free_root(&stmt->extension->fields_mem_root, MYF(0));
4704 
4705   if (mysql)
4706   {
4707     mysql->stmts= list_delete(mysql->stmts, &stmt->list);
4708     /*
4709      Clear NET error state: if the following commands come through
4710      successfully, connection will still be usable for other commands.
4711     */
4712     net_clear_error(&mysql->net);
4713 
4714     if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE)
4715     {
4716       uchar buff[MYSQL_STMT_HEADER];             /* 4 bytes - stmt id */
4717 
4718       reset_stmt_handle(stmt, RESET_ALL_BUFFERS | RESET_CLEAR_ERROR);
4719 
4720       int4store(buff, stmt->stmt_id);
4721       if ((rc= stmt_command(mysql, COM_STMT_CLOSE, buff, 4, stmt)))
4722       {
4723         set_stmt_errmsg(stmt, &mysql->net);
4724       }
4725     }
4726   }
4727 
4728   my_free(stmt->extension);
4729   my_free(stmt);
4730 
4731   DBUG_RETURN(MY_TEST(rc));
4732 }
4733 
4734 /*
4735   Reset the statement buffers in server
4736 */
4737 
4738 my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt)
4739 {
4740   DBUG_ENTER("mysql_stmt_reset");
4741   DBUG_ASSERT(stmt != 0);
4742   if (!stmt->mysql)
4743   {
4744     /* mysql can be reset in mysql_close called from mysql_reconnect */
4745     set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL);
4746     DBUG_RETURN(1);
4747   }
4748   /* Reset the client and server sides of the prepared statement */
4749   DBUG_RETURN(reset_stmt_handle(stmt,
4750                                 RESET_SERVER_SIDE | RESET_LONG_DATA |
4751                                 RESET_ALL_BUFFERS | RESET_CLEAR_ERROR));
4752 }
4753 
4754 /*
4755   Return statement error code
4756 */
4757 
4758 uint STDCALL mysql_stmt_errno(MYSQL_STMT * stmt)
4759 {
4760   DBUG_ENTER("mysql_stmt_errno");
4761   DBUG_RETURN(stmt->last_errno);
4762 }
4763 
4764 const char *STDCALL mysql_stmt_sqlstate(MYSQL_STMT * stmt)
4765 {
4766   DBUG_ENTER("mysql_stmt_sqlstate");
4767   DBUG_RETURN(stmt->sqlstate);
4768 }
4769 
4770 /*
4771   Return statement error message
4772 */
4773 
4774 const char *STDCALL mysql_stmt_error(MYSQL_STMT * stmt)
4775 {
4776   DBUG_ENTER("mysql_stmt_error");
4777   DBUG_RETURN(stmt->last_error);
4778 }
4779 
4780 
4781 /********************************************************************
4782  Transactional APIs
4783 *********************************************************************/
4784 
4785 /*
4786   Commit the current transaction
4787 */
4788 
4789 my_bool STDCALL mysql_commit(MYSQL * mysql)
4790 {
4791   DBUG_ENTER("mysql_commit");
4792   DBUG_RETURN((my_bool) mysql_real_query(mysql, "commit", 6));
4793 }
4794 
4795 /*
4796   Rollback the current transaction
4797 */
4798 
4799 my_bool STDCALL mysql_rollback(MYSQL * mysql)
4800 {
4801   DBUG_ENTER("mysql_rollback");
4802   DBUG_RETURN((my_bool) mysql_real_query(mysql, "rollback", 8));
4803 }
4804 
4805 
4806 /*
4807   Set autocommit to either true or false
4808 */
4809 
4810 my_bool STDCALL mysql_autocommit(MYSQL * mysql, my_bool auto_mode)
4811 {
4812   DBUG_ENTER("mysql_autocommit");
4813   DBUG_PRINT("enter", ("mode : %d", auto_mode));
4814 
4815   DBUG_RETURN((my_bool) mysql_real_query(mysql, auto_mode ?
4816                                          "set autocommit=1":"set autocommit=0",
4817                                          16));
4818 }
4819 
4820 
4821 /********************************************************************
4822  Multi query execution + SPs APIs
4823 *********************************************************************/
4824 
4825 /*
4826   Returns true/false to indicate whether any more query results exist
4827   to be read using mysql_next_result()
4828 */
4829 
4830 my_bool STDCALL mysql_more_results(MYSQL *mysql)
4831 {
4832   my_bool res;
4833   DBUG_ENTER("mysql_more_results");
4834 
4835   res= ((mysql->server_status & SERVER_MORE_RESULTS_EXISTS) ? 1: 0);
4836   DBUG_PRINT("exit",("More results exists ? %d", res));
4837   DBUG_RETURN(res);
4838 }
4839 
4840 
4841 /*
4842   Reads and returns the next query results
4843 */
4844 int STDCALL mysql_next_result(MYSQL *mysql)
4845 {
4846   DBUG_ENTER("mysql_next_result");
4847 
4848   if (mysql->status != MYSQL_STATUS_READY)
4849   {
4850     set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
4851     DBUG_RETURN(1);
4852   }
4853 
4854   net_clear_error(&mysql->net);
4855   mysql->affected_rows= ~(my_ulonglong) 0;
4856 
4857   if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
4858     DBUG_RETURN((*mysql->methods->next_result)(mysql));
4859 
4860   DBUG_RETURN(-1);				/* No more results */
4861 }
4862 
4863 int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt)
4864 {
4865   MYSQL *mysql= stmt->mysql;
4866   int rc;
4867   DBUG_ENTER("mysql_stmt_next_result");
4868 
4869   if (!mysql)
4870     DBUG_RETURN(1);
4871 
4872   if (stmt->last_errno)
4873     DBUG_RETURN(stmt->last_errno);
4874 
4875   if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
4876   {
4877     if (reset_stmt_handle(stmt, RESET_STORE_RESULT))
4878       DBUG_RETURN(1);
4879   }
4880 
4881   rc= mysql_next_result(mysql);
4882 
4883   if (rc)
4884   {
4885     set_stmt_errmsg(stmt, &mysql->net);
4886     DBUG_RETURN(rc);
4887   }
4888 
4889   if (mysql->status == MYSQL_STATUS_GET_RESULT)
4890     mysql->status= MYSQL_STATUS_STATEMENT_GET_RESULT;
4891 
4892   stmt->state= MYSQL_STMT_EXECUTE_DONE;
4893   stmt->bind_result_done= FALSE;
4894   stmt->field_count= mysql->field_count;
4895 
4896   if (mysql->field_count)
4897   {
4898     alloc_stmt_fields(stmt);
4899     prepare_to_fetch_result(stmt);
4900   }
4901 
4902   DBUG_RETURN(0);
4903 }
4904 
4905 
4906 MYSQL_RES * STDCALL mysql_use_result(MYSQL *mysql)
4907 {
4908   return (*mysql->methods->use_result)(mysql);
4909 }
4910 
4911 my_bool STDCALL mysql_read_query_result(MYSQL *mysql)
4912 {
4913   return (*mysql->methods->read_query_result)(mysql);
4914 }
4915 
4916 /********************************************************************
4917   mysql_net_ functions - low-level API to MySQL protocol
4918 *********************************************************************/
4919 ulong STDCALL mysql_net_read_packet(MYSQL *mysql)
4920 {
4921   return cli_safe_read(mysql);
4922 }
4923 
4924 ulong STDCALL mysql_net_field_length(uchar **packet)
4925 {
4926   return net_field_length(packet);
4927 }
4928