~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to libmysql/libmysql.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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