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