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