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= ¶m->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= ¶m->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= ¶m->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= ¶m->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= ¶m->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= ¶m->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= ¶m->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= ¶m->is_null_value;
4118
4119 if (!param->length)
4120 param->length= ¶m->length_value;
4121
4122 if (!param->error)
4123 param->error= ¶m->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= ¶m->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