~drizzle-trunk/drizzle/development

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