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