~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000-2004 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation.
6
7
   There are special exceptions to the terms and conditions of the GPL as it
8
   is applied to this software. View the full text of the exception in file
9
   EXCEPTIONS-CLIENT in the directory of this software distribution.
10
11
   This program is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
   GNU General Public License for more details.
15
16
   You should have received a copy of the GNU General Public License
17
   along with this program; if not, write to the Free Software
18
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
19
20
#include <my_global.h>
21
#include <my_sys.h>
22
#include <my_time.h>
23
#include <mysys_err.h>
24
#include <m_string.h>
25
#include <m_ctype.h>
77.1.39 by Monty Taylor
More mysql->drizzle renaming.
26
#include "drizzle.h"
27
#include "drizzle_version.h"
1 by brian
clean slate
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
94 by Brian Aker
DOS removal. DOS... hard to believe aye?
37
1 by brian
clean slate
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
94 by Brian Aker
DOS removal. DOS... hard to believe aye?
48
1 by brian
clean slate
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
#include <my_pthread.h>				/* because of signal()	*/
56
#ifndef INADDR_NONE
57
#define INADDR_NONE	-1
58
#endif
59
60
#include <sql_common.h>
61
#include "client_settings.h"
62
63
#undef net_buffer_length
64
#undef max_allowed_packet
65
66
ulong 		net_buffer_length=8192;
67
ulong		max_allowed_packet= 1024L*1024L*1024L;
68
69
#include <errno.h>
70
#define SOCKET_ERROR -1
71
72
/*
73
  If allowed through some configuration, then this needs to
74
  be changed
75
*/
76
#define MAX_LONG_DATA_LENGTH 8192
77
#define unsigned_field(A) ((A)->flags & UNSIGNED_FLAG)
78
79
static void append_wild(char *to,char *end,const char *wild);
80
81
static my_bool mysql_client_init= 0;
82
static my_bool org_my_init_done= 0;
83
84
85
/*
86
  Initialize the MySQL client library
87
88
  SYNOPSIS
89
    mysql_server_init()
90
91
  NOTES
92
    Should be called before doing any other calls to the MySQL
93
    client library to initialize thread specific variables etc.
94
    It's called by mysql_init() to ensure that things will work for
95
    old not threaded applications that doesn't call mysql_server_init()
96
    directly.
97
98
  RETURN
99
    0  ok
100
    1  could not initialize environment (out of memory or thread keys)
101
*/
102
103
int STDCALL mysql_server_init(int argc __attribute__((unused)),
104
			      char **argv __attribute__((unused)),
105
			      char **groups __attribute__((unused)))
106
{
107
  int result= 0;
108
  if (!mysql_client_init)
109
  {
110
    mysql_client_init=1;
111
    org_my_init_done=my_init_done;
112
    if (my_init())				/* Will init threads */
113
      return 1;
114
    init_client_errs();
115
    if (!mysql_port)
116
    {
117
      mysql_port = MYSQL_PORT;
118
      {
119
	struct servent *serv_ptr;
120
	char	*env;
121
122
        /*
123
          if builder specifically requested a default port, use that
124
          (even if it coincides with our factory default).
125
          only if they didn't do we check /etc/services (and, failing
126
          on that, fall back to the factory default of 3306).
127
          either default can be overridden by the environment variable
128
          MYSQL_TCP_PORT, which in turn can be overridden with command
129
          line options.
130
        */
131
132
#if MYSQL_PORT_DEFAULT == 0
133
        if ((serv_ptr = getservbyname("mysql", "tcp")))
134
          mysql_port = (uint) ntohs((ushort) serv_ptr->s_port);
135
#endif
136
        if ((env = getenv("MYSQL_TCP_PORT")))
137
          mysql_port =(uint) atoi(env);
138
      }
139
    }
140
    if (!mysql_unix_port)
141
    {
142
      char *env;
143
      mysql_unix_port = (char*) MYSQL_UNIX_ADDR;
144
      if ((env = getenv("MYSQL_UNIX_PORT")))
145
	mysql_unix_port = env;
146
    }
147
    mysql_debug(NullS);
47 by Brian Aker
First pass on removing binary protocol from client library.
148
#if defined(SIGPIPE)
1 by brian
clean slate
149
    (void) signal(SIGPIPE, SIG_IGN);
150
#endif
151
  }
152
  else
153
    result= (int)my_thread_init();         /* Init if new thread */
154
  return result;
155
}
156
157
158
/*
159
  Free all memory and resources used by the client library
160
161
  NOTES
162
    When calling this there should not be any other threads using
163
    the library.
164
165
    To make things simpler when used with windows dll's (which calls this
166
    function automaticly), it's safe to call this function multiple times.
167
*/
168
169
170
void STDCALL mysql_server_end()
171
{
172
  if (!mysql_client_init)
173
    return;
174
175
  finish_client_errs();
176
  vio_end();
177
178
  /* If library called my_init(), free memory allocated by it */
179
  if (!org_my_init_done)
180
  {
181
    my_end(MY_DONT_FREE_DBUG);
182
    /* Remove TRACING, if enabled by mysql_debug() */
183
    DBUG_POP();
184
  }
185
  else
186
  {
187
    free_charsets();
188
    mysql_thread_end();
189
  }
190
191
  mysql_client_init= org_my_init_done= 0;
192
#ifdef EMBEDDED_SERVER
193
  if (stderror_file)
194
  {
195
    fclose(stderror_file);
196
    stderror_file= 0;
197
  }
198
#endif
199
}
200
201
static MYSQL_PARAMETERS mysql_internal_parameters=
202
{&max_allowed_packet, &net_buffer_length, 0};
203
204
MYSQL_PARAMETERS *STDCALL mysql_get_parameters(void)
205
{
206
  return &mysql_internal_parameters;
207
}
208
209
my_bool STDCALL mysql_thread_init()
210
{
211
  return my_thread_init();
212
}
213
214
void STDCALL mysql_thread_end()
215
{
216
  my_thread_end();
217
}
218
219
220
/*
221
  Expand wildcard to a sql string
222
*/
223
224
static void
225
append_wild(char *to, char *end, const char *wild)
226
{
227
  end-=5;					/* Some extra */
228
  if (wild && wild[0])
229
  {
230
    to=strmov(to," like '");
231
    while (*wild && to < end)
232
    {
233
      if (*wild == '\\' || *wild == '\'')
234
	*to++='\\';
235
      *to++= *wild++;
236
    }
237
    if (*wild)					/* Too small buffer */
238
      *to++='%';				/* Nicer this way */
239
    to[0]='\'';
240
    to[1]=0;
241
  }
242
}
243
244
245
/**************************************************************************
246
  Init debugging if MYSQL_DEBUG environment variable is found
247
**************************************************************************/
248
249
void STDCALL
250
mysql_debug(const char *debug __attribute__((unused)))
251
{
252
#ifndef DBUG_OFF
253
  char	*env;
254
  if (debug)
255
  {
256
    DBUG_PUSH(debug);
257
  }
258
  else if ((env = getenv("MYSQL_DEBUG")))
259
  {
260
    DBUG_PUSH(env);
261
#if !defined(_WINVER) && !defined(WINVER)
262
    puts("\n-------------------------------------------------------");
263
    puts("MYSQL_DEBUG found. libmysql started with the following:");
264
    puts(env);
265
    puts("-------------------------------------------------------\n");
266
#else
267
    {
268
      char buff[80];
269
      buff[sizeof(buff)-1]= 0;
270
      strxnmov(buff,sizeof(buff)-1,"libmysql: ", env, NullS);
271
      MessageBox((HWND) 0,"Debugging variable MYSQL_DEBUG used",buff,MB_OK);
272
    }
273
#endif
274
  }
275
#endif
276
}
277
278
279
/**************************************************************************
280
  Ignore SIGPIPE handler
281
   ARGSUSED
282
**************************************************************************/
283
284
sig_handler
285
my_pipe_sig_handler(int sig __attribute__((unused)))
286
{
287
  DBUG_PRINT("info",("Hit by signal %d",sig));
288
#ifdef DONT_REMEMBER_SIGNAL
289
  (void) signal(SIGPIPE, my_pipe_sig_handler);
290
#endif
291
}
292
293
294
/**************************************************************************
295
  Connect to sql server
296
  If host == 0 then use localhost
297
**************************************************************************/
298
299
#ifdef USE_OLD_FUNCTIONS
300
MYSQL * STDCALL
301
mysql_connect(MYSQL *mysql,const char *host,
302
	      const char *user, const char *passwd)
303
{
304
  MYSQL *res;
305
  mysql=mysql_init(mysql);			/* Make it thread safe */
306
  {
307
    DBUG_ENTER("mysql_connect");
308
    if (!(res=mysql_real_connect(mysql,host,user,passwd,NullS,0,NullS,0)))
309
    {
310
      if (mysql->free_me)
311
	my_free((uchar*) mysql,MYF(0));
312
    }
313
    mysql->reconnect= 1;
314
    DBUG_RETURN(res);
315
  }
316
}
317
#endif
318
319
320
/**************************************************************************
321
  Change user and database
322
**************************************************************************/
323
324
int cli_read_change_user_result(MYSQL *mysql, char *buff, const char *passwd)
325
{
326
  NET *net= &mysql->net;
327
  ulong pkt_length;
328
329
  pkt_length= cli_safe_read(mysql);
330
  
331
  if (pkt_length == packet_error)
332
    return 1;
333
334
  if (pkt_length == 1 && net->read_pos[0] == 254 &&
335
      mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
336
  {
337
    /*
338
      By sending this very specific reply server asks us to send scrambled
339
      password in old format. The reply contains scramble_323.
340
    */
341
    scramble_323(buff, mysql->scramble, passwd);
342
    if (my_net_write(net, (uchar*) buff, SCRAMBLE_LENGTH_323 + 1) ||
343
        net_flush(net))
344
    {
345
      set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate);
346
      return 1;
347
    }
348
    /* Read what server thinks about out new auth message report */
349
    if (cli_safe_read(mysql) == packet_error)
350
      return 1;
351
  }
352
  return 0;
353
}
354
355
my_bool	STDCALL mysql_change_user(MYSQL *mysql, const char *user,
356
				  const char *passwd, const char *db)
357
{
358
  char buff[USERNAME_LENGTH+SCRAMBLED_PASSWORD_CHAR_LENGTH+NAME_LEN+2];
359
  char *end= buff;
360
  int rc;
361
  CHARSET_INFO *saved_cs= mysql->charset;
362
363
  DBUG_ENTER("mysql_change_user");
364
365
  /* Get the connection-default character set. */
366
367
  if (mysql_init_character_set(mysql))
368
  {
369
    mysql->charset= saved_cs;
370
    DBUG_RETURN(TRUE);
371
  }
372
373
  /* Use an empty string instead of NULL. */
374
375
  if (!user)
376
    user="";
377
  if (!passwd)
378
    passwd="";
379
380
  /* Store user into the buffer */
381
  end= strmake(end, user, USERNAME_LENGTH) + 1;
382
383
  /* write scrambled password according to server capabilities */
384
  if (passwd[0])
385
  {
386
    if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
387
    {
388
      *end++= SCRAMBLE_LENGTH;
389
      scramble(end, mysql->scramble, passwd);
390
      end+= SCRAMBLE_LENGTH;
391
    }
392
    else
393
    {
394
      scramble_323(end, mysql->scramble, passwd);
395
      end+= SCRAMBLE_LENGTH_323 + 1;
396
    }
397
  }
398
  else
399
    *end++= '\0';                               /* empty password */
400
  /* Add database if needed */
401
  end= strmake(end, db ? db : "", NAME_LEN) + 1;
402
403
  /* Add character set number. */
404
405
  if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
406
  {
407
    int2store(end, (ushort) mysql->charset->number);
408
    end+= 2;
409
  }
410
411
  /* Write authentication package */
412
  simple_command(mysql,COM_CHANGE_USER, (uchar*) buff, (ulong) (end-buff), 1);
413
414
  rc= (*mysql->methods->read_change_user_result)(mysql, buff, passwd);
415
416
  if (rc == 0)
417
  {
418
    /* Free old connect information */
419
    my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
420
    my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR));
421
    my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR));
422
423
    /* alloc new connect information */
424
    mysql->user=  my_strdup(user,MYF(MY_WME));
425
    mysql->passwd=my_strdup(passwd,MYF(MY_WME));
426
    mysql->db=    db ? my_strdup(db,MYF(MY_WME)) : 0;
427
  }
428
  else
429
  {
430
    mysql->charset= saved_cs;
431
  }
432
433
  DBUG_RETURN(rc);
434
}
435
436
#if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
437
struct passwd *getpwuid(uid_t);
438
char* getlogin(void);
439
#endif
440
441
void read_user_name(char *name)
442
{
443
  DBUG_ENTER("read_user_name");
444
  if (geteuid() == 0)
445
    (void) strmov(name,"root");		/* allow use of surun */
446
  else
447
  {
448
#ifdef HAVE_GETPWUID
449
    struct passwd *skr;
450
    const char *str;
451
    if ((str=getlogin()) == NULL)
452
    {
453
      if ((skr=getpwuid(geteuid())) != NULL)
454
	str=skr->pw_name;
455
      else if (!(str=getenv("USER")) && !(str=getenv("LOGNAME")) &&
456
	       !(str=getenv("LOGIN")))
457
	str="UNKNOWN_USER";
458
    }
459
    (void) strmake(name,str,USERNAME_LENGTH);
460
#elif HAVE_CUSERID
461
    (void) cuserid(name);
462
#else
463
    strmov(name,"UNKNOWN_USER");
464
#endif
465
  }
466
  DBUG_VOID_RETURN;
467
}
468
469
my_bool handle_local_infile(MYSQL *mysql, const char *net_filename)
470
{
471
  my_bool result= 1;
472
  uint packet_length=MY_ALIGN(mysql->net.max_packet-16,IO_SIZE);
473
  NET *net= &mysql->net;
474
  int readcount;
475
  void *li_ptr;          /* pass state to local_infile functions */
476
  char *buf;		/* buffer to be filled by local_infile_read */
477
  struct st_mysql_options *options= &mysql->options;
478
  DBUG_ENTER("handle_local_infile");
479
480
  /* check that we've got valid callback functions */
481
  if (!(options->local_infile_init &&
482
	options->local_infile_read &&
483
	options->local_infile_end &&
484
	options->local_infile_error))
485
  {
486
    /* if any of the functions is invalid, set the default */
487
    mysql_set_local_infile_default(mysql);
488
  }
489
490
  /* copy filename into local memory and allocate read buffer */
491
  if (!(buf=my_malloc(packet_length, MYF(0))))
492
  {
493
    set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
494
    DBUG_RETURN(1);
495
  }
496
497
  /* initialize local infile (open file, usually) */
498
  if ((*options->local_infile_init)(&li_ptr, net_filename,
499
    options->local_infile_userdata))
500
  {
501
    VOID(my_net_write(net,(const uchar*) "",0)); /* Server needs one packet */
502
    net_flush(net);
503
    strmov(net->sqlstate, unknown_sqlstate);
504
    net->last_errno=
505
      (*options->local_infile_error)(li_ptr,
506
                                     net->last_error,
507
                                     sizeof(net->last_error)-1);
508
    goto err;
509
  }
510
511
  /* read blocks of data from local infile callback */
512
  while ((readcount =
513
	  (*options->local_infile_read)(li_ptr, buf,
514
					packet_length)) > 0)
515
  {
516
    if (my_net_write(net, (uchar*) buf, readcount))
517
    {
518
      DBUG_PRINT("error",
519
		 ("Lost connection to MySQL server during LOAD DATA of local file"));
520
      set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate);
521
      goto err;
522
    }
523
  }
524
525
  /* Send empty packet to mark end of file */
526
  if (my_net_write(net, (const uchar*) "", 0) || net_flush(net))
527
  {
528
    set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate);
529
    goto err;
530
  }
531
532
  if (readcount < 0)
533
  {
534
    net->last_errno=
535
      (*options->local_infile_error)(li_ptr,
536
                                     net->last_error,
537
                                     sizeof(net->last_error)-1);
538
    goto err;
539
  }
540
541
  result=0;					/* Ok */
542
543
err:
544
  /* free up memory allocated with _init, usually */
545
  (*options->local_infile_end)(li_ptr);
546
  my_free(buf, MYF(0));
547
  DBUG_RETURN(result);
548
}
549
550
551
/****************************************************************************
552
  Default handlers for LOAD LOCAL INFILE
553
****************************************************************************/
554
555
typedef struct st_default_local_infile
556
{
557
  int fd;
558
  int error_num;
559
  const char *filename;
560
  char error_msg[LOCAL_INFILE_ERROR_LEN];
561
} default_local_infile_data;
562
563
564
/*
565
  Open file for LOAD LOCAL INFILE
566
567
  SYNOPSIS
568
    default_local_infile_init()
569
    ptr			Store pointer to internal data here
570
    filename		File name to open. This may be in unix format !
571
572
573
  NOTES
574
    Even if this function returns an error, the load data interface
575
    guarantees that default_local_infile_end() is called.
576
577
  RETURN
578
    0	ok
579
    1	error
580
*/
581
582
static int default_local_infile_init(void **ptr, const char *filename,
583
             void *userdata __attribute__ ((unused)))
584
{
585
  default_local_infile_data *data;
586
  char tmp_name[FN_REFLEN];
587
588
  if (!(*ptr= data= ((default_local_infile_data *)
589
		     my_malloc(sizeof(default_local_infile_data),  MYF(0)))))
590
    return 1; /* out of memory */
591
592
  data->error_msg[0]= 0;
593
  data->error_num=    0;
594
  data->filename= filename;
595
596
  fn_format(tmp_name, filename, "", "", MY_UNPACK_FILENAME);
597
  if ((data->fd = my_open(tmp_name, O_RDONLY, MYF(0))) < 0)
598
  {
599
    data->error_num= my_errno;
77.1.18 by Monty Taylor
Removed my_vsnprintf and my_snprintf.
600
    snprintf(data->error_msg, sizeof(data->error_msg)-1,
601
             EE(EE_FILENOTFOUND), tmp_name, data->error_num);
1 by brian
clean slate
602
    return 1;
603
  }
604
  return 0; /* ok */
605
}
606
607
608
/*
609
  Read data for LOAD LOCAL INFILE
610
611
  SYNOPSIS
612
    default_local_infile_read()
613
    ptr			Points to handle allocated by _init
614
    buf			Read data here
615
    buf_len		Ammount of data to read
616
617
  RETURN
618
    > 0		number of bytes read
619
    == 0	End of data
620
    < 0		Error
621
*/
622
623
static int default_local_infile_read(void *ptr, char *buf, uint buf_len)
624
{
625
  int count;
626
  default_local_infile_data*data = (default_local_infile_data *) ptr;
627
628
  if ((count= (int) my_read(data->fd, (uchar *) buf, buf_len, MYF(0))) < 0)
629
  {
630
    data->error_num= EE_READ; /* the errmsg for not entire file read */
77.1.18 by Monty Taylor
Removed my_vsnprintf and my_snprintf.
631
    snprintf(data->error_msg, sizeof(data->error_msg)-1,
632
             EE(EE_READ),
633
             data->filename, my_errno);
1 by brian
clean slate
634
  }
635
  return count;
636
}
637
638
639
/*
640
  Read data for LOAD LOCAL INFILE
641
642
  SYNOPSIS
643
    default_local_infile_end()
644
    ptr			Points to handle allocated by _init
645
			May be NULL if _init failed!
646
647
  RETURN
648
*/
649
650
static void default_local_infile_end(void *ptr)
651
{
652
  default_local_infile_data *data= (default_local_infile_data *) ptr;
653
  if (data)					/* If not error on open */
654
  {
655
    if (data->fd >= 0)
656
      my_close(data->fd, MYF(MY_WME));
657
    my_free(ptr, MYF(MY_WME));
658
  }
659
}
660
661
662
/*
663
  Return error from LOAD LOCAL INFILE
664
665
  SYNOPSIS
666
    default_local_infile_end()
667
    ptr			Points to handle allocated by _init
668
			May be NULL if _init failed!
669
    error_msg		Store error text here
670
    error_msg_len	Max lenght of error_msg
671
672
  RETURN
673
    error message number
674
*/
675
676
static int
677
default_local_infile_error(void *ptr, char *error_msg, uint error_msg_len)
678
{
679
  default_local_infile_data *data = (default_local_infile_data *) ptr;
680
  if (data)					/* If not error on open */
681
  {
682
    strmake(error_msg, data->error_msg, error_msg_len);
683
    return data->error_num;
684
  }
685
  /* This can only happen if we got error on malloc of handle */
686
  strmov(error_msg, ER(CR_OUT_OF_MEMORY));
687
  return CR_OUT_OF_MEMORY;
688
}
689
690
691
void
692
mysql_set_local_infile_handler(MYSQL *mysql,
693
                               int (*local_infile_init)(void **, const char *,
694
                               void *),
695
                               int (*local_infile_read)(void *, char *, uint),
696
                               void (*local_infile_end)(void *),
697
                               int (*local_infile_error)(void *, char *, uint),
698
                               void *userdata)
699
{
700
  mysql->options.local_infile_init=  local_infile_init;
701
  mysql->options.local_infile_read=  local_infile_read;
702
  mysql->options.local_infile_end=   local_infile_end;
703
  mysql->options.local_infile_error= local_infile_error;
704
  mysql->options.local_infile_userdata = userdata;
705
}
706
707
708
void mysql_set_local_infile_default(MYSQL *mysql)
709
{
710
  mysql->options.local_infile_init=  default_local_infile_init;
711
  mysql->options.local_infile_read=  default_local_infile_read;
712
  mysql->options.local_infile_end=   default_local_infile_end;
713
  mysql->options.local_infile_error= default_local_infile_error;
714
}
715
716
717
/**************************************************************************
718
  Do a query. If query returned rows, free old rows.
719
  Read data by mysql_store_result or by repeat call of mysql_fetch_row
720
**************************************************************************/
721
722
int STDCALL
723
mysql_query(MYSQL *mysql, const char *query)
724
{
725
  return mysql_real_query(mysql,query, (uint) strlen(query));
726
}
727
728
729
/**************************************************************************
730
  Return next field of the query results
731
**************************************************************************/
732
733
MYSQL_FIELD * STDCALL
734
mysql_fetch_field(MYSQL_RES *result)
735
{
736
  if (result->current_field >= result->field_count)
737
    return(NULL);
738
  return &result->fields[result->current_field++];
739
}
740
741
742
/**************************************************************************
743
  Move to a specific row and column
744
**************************************************************************/
745
746
void STDCALL
747
mysql_data_seek(MYSQL_RES *result, my_ulonglong row)
748
{
749
  MYSQL_ROWS	*tmp=0;
750
  DBUG_PRINT("info",("mysql_data_seek(%ld)",(long) row));
751
  if (result->data)
752
    for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ;
753
  result->current_row=0;
754
  result->data_cursor = tmp;
755
}
756
757
758
/*************************************************************************
759
  put the row or field cursor one a position one got from mysql_row_tell()
760
  This doesn't restore any data. The next mysql_fetch_row or
761
  mysql_fetch_field will return the next row or field after the last used
762
*************************************************************************/
763
764
MYSQL_ROW_OFFSET STDCALL
765
mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET row)
766
{
767
  MYSQL_ROW_OFFSET return_value=result->data_cursor;
768
  result->current_row= 0;
769
  result->data_cursor= row;
770
  return return_value;
771
}
772
773
774
MYSQL_FIELD_OFFSET STDCALL
775
mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET field_offset)
776
{
777
  MYSQL_FIELD_OFFSET return_value=result->current_field;
778
  result->current_field=field_offset;
779
  return return_value;
780
}
781
782
783
/*****************************************************************************
784
  List all databases
785
*****************************************************************************/
786
787
MYSQL_RES * STDCALL
788
mysql_list_dbs(MYSQL *mysql, const char *wild)
789
{
790
  char buff[255];
791
  DBUG_ENTER("mysql_list_dbs");
792
793
  append_wild(strmov(buff,"show databases"),buff+sizeof(buff),wild);
794
  if (mysql_query(mysql,buff))
795
    DBUG_RETURN(0);
796
  DBUG_RETURN (mysql_store_result(mysql));
797
}
798
799
800
/*****************************************************************************
801
  List all tables in a database
802
  If wild is given then only the tables matching wild is returned
803
*****************************************************************************/
804
805
MYSQL_RES * STDCALL
806
mysql_list_tables(MYSQL *mysql, const char *wild)
807
{
808
  char buff[255];
809
  DBUG_ENTER("mysql_list_tables");
810
811
  append_wild(strmov(buff,"show tables"),buff+sizeof(buff),wild);
812
  if (mysql_query(mysql,buff))
813
    DBUG_RETURN(0);
814
  DBUG_RETURN (mysql_store_result(mysql));
815
}
816
817
818
MYSQL_FIELD *cli_list_fields(MYSQL *mysql)
819
{
820
  MYSQL_DATA *query;
821
  if (!(query= cli_read_rows(mysql,(MYSQL_FIELD*) 0, 
822
			     protocol_41(mysql) ? 8 : 6)))
823
    return NULL;
824
825
  mysql->field_count= (uint) query->rows;
826
  return unpack_fields(query,&mysql->field_alloc,
827
		       mysql->field_count, 1, mysql->server_capabilities);
828
}
829
830
831
/**************************************************************************
832
  List all fields in a table
833
  If wild is given then only the fields matching wild is returned
834
  Instead of this use query:
835
  show fields in 'table' like "wild"
836
**************************************************************************/
837
838
MYSQL_RES * STDCALL
839
mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)
840
{
841
  MYSQL_RES   *result;
842
  MYSQL_FIELD *fields;
843
  char	     buff[257],*end;
844
  DBUG_ENTER("mysql_list_fields");
845
  DBUG_PRINT("enter",("table: '%s'  wild: '%s'",table,wild ? wild : ""));
846
847
  end=strmake(strmake(buff, table,128)+1,wild ? wild : "",128);
848
  free_old_query(mysql);
849
  if (simple_command(mysql, COM_FIELD_LIST, (uchar*) buff,
850
                     (ulong) (end-buff), 1) ||
851
      !(fields= (*mysql->methods->list_fields)(mysql)))
852
    DBUG_RETURN(NULL);
853
854
  if (!(result = (MYSQL_RES *) my_malloc(sizeof(MYSQL_RES),
855
					 MYF(MY_WME | MY_ZEROFILL))))
856
    DBUG_RETURN(NULL);
857
858
  result->methods= mysql->methods;
859
  result->field_alloc=mysql->field_alloc;
860
  mysql->fields=0;
861
  result->field_count = mysql->field_count;
862
  result->fields= fields;
863
  result->eof=1;
864
  DBUG_RETURN(result);
865
}
866
867
/* List all running processes (threads) in server */
868
869
MYSQL_RES * STDCALL
870
mysql_list_processes(MYSQL *mysql)
871
{
872
  MYSQL_DATA *fields;
873
  uint field_count;
874
  uchar *pos;
875
  DBUG_ENTER("mysql_list_processes");
876
877
  if (simple_command(mysql,COM_PROCESS_INFO,0,0,0))
878
    DBUG_RETURN(0);
879
  free_old_query(mysql);
880
  pos=(uchar*) mysql->net.read_pos;
881
  field_count=(uint) net_field_length(&pos);
882
  if (!(fields = (*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*) 0,
883
					      protocol_41(mysql) ? 7 : 5)))
884
    DBUG_RETURN(NULL);
885
  if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,field_count,0,
886
				    mysql->server_capabilities)))
887
    DBUG_RETURN(0);
888
  mysql->status=MYSQL_STATUS_GET_RESULT;
889
  mysql->field_count=field_count;
890
  DBUG_RETURN(mysql_store_result(mysql));
891
}
892
893
894
#ifdef USE_OLD_FUNCTIONS
895
int  STDCALL
896
mysql_create_db(MYSQL *mysql, const char *db)
897
{
898
  DBUG_ENTER("mysql_createdb");
899
  DBUG_PRINT("enter",("db: %s",db));
900
  DBUG_RETURN(simple_command(mysql,COM_CREATE_DB,db, (ulong) strlen(db),0));
901
}
902
903
904
int  STDCALL
905
mysql_drop_db(MYSQL *mysql, const char *db)
906
{
907
  DBUG_ENTER("mysql_drop_db");
908
  DBUG_PRINT("enter",("db: %s",db));
909
  DBUG_RETURN(simple_command(mysql,COM_DROP_DB,db,(ulong) strlen(db),0));
910
}
911
#endif
912
913
914
int STDCALL
915
mysql_shutdown(MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level)
916
{
917
  uchar level[1];
918
  DBUG_ENTER("mysql_shutdown");
919
  level[0]= (uchar) shutdown_level;
920
  DBUG_RETURN(simple_command(mysql, COM_SHUTDOWN, level, 1, 0));
921
}
922
923
924
int STDCALL
925
mysql_refresh(MYSQL *mysql,uint options)
926
{
927
  uchar bits[1];
928
  DBUG_ENTER("mysql_refresh");
929
  bits[0]= (uchar) options;
930
  DBUG_RETURN(simple_command(mysql, COM_REFRESH, bits, 1, 0));
931
}
932
933
934
int STDCALL
935
mysql_kill(MYSQL *mysql,ulong pid)
936
{
937
  uchar buff[4];
938
  DBUG_ENTER("mysql_kill");
939
  int4store(buff,pid);
940
  DBUG_RETURN(simple_command(mysql,COM_PROCESS_KILL,buff,sizeof(buff),0));
941
}
942
943
944
int STDCALL
945
mysql_set_server_option(MYSQL *mysql, enum enum_mysql_set_option option)
946
{
947
  uchar buff[2];
948
  DBUG_ENTER("mysql_set_server_option");
949
  int2store(buff, (uint) option);
950
  DBUG_RETURN(simple_command(mysql, COM_SET_OPTION, buff, sizeof(buff), 0));
951
}
952
953
954
int STDCALL
955
mysql_dump_debug_info(MYSQL *mysql)
956
{
957
  DBUG_ENTER("mysql_dump_debug_info");
958
  DBUG_RETURN(simple_command(mysql,COM_DEBUG,0,0,0));
959
}
960
961
962
const char *cli_read_statistics(MYSQL *mysql)
963
{
964
  mysql->net.read_pos[mysql->packet_length]=0;	/* End of stat string */
965
  if (!mysql->net.read_pos[0])
966
  {
967
    set_mysql_error(mysql, CR_WRONG_HOST_INFO, unknown_sqlstate);
968
    return mysql->net.last_error;
969
  }
970
  return (char*) mysql->net.read_pos;
971
}
972
973
974
const char * STDCALL
975
mysql_stat(MYSQL *mysql)
976
{
977
  DBUG_ENTER("mysql_stat");
978
  if (simple_command(mysql,COM_STATISTICS,0,0,0))
979
    DBUG_RETURN(mysql->net.last_error);
980
  DBUG_RETURN((*mysql->methods->read_statistics)(mysql));
981
}
982
983
984
int STDCALL
985
mysql_ping(MYSQL *mysql)
986
{
987
  int res;
988
  DBUG_ENTER("mysql_ping");
989
  res= simple_command(mysql,COM_PING,0,0,0);
990
  if (res == CR_SERVER_LOST && mysql->reconnect)
991
    res= simple_command(mysql,COM_PING,0,0,0);
992
  DBUG_RETURN(res);
993
}
994
995
996
const char * STDCALL
997
mysql_get_server_info(MYSQL *mysql)
998
{
999
  return((char*) mysql->server_version);
1000
}
1001
1002
1003
const char * STDCALL
1004
mysql_get_host_info(MYSQL *mysql)
1005
{
1006
  return(mysql->host_info);
1007
}
1008
1009
1010
uint STDCALL
1011
mysql_get_proto_info(MYSQL *mysql)
1012
{
1013
  return (mysql->protocol_version);
1014
}
1015
1016
const char * STDCALL
1017
mysql_get_client_info(void)
1018
{
1019
  return (char*) MYSQL_SERVER_VERSION;
1020
}
1021
1022
ulong STDCALL mysql_get_client_version(void)
1023
{
1024
  return MYSQL_VERSION_ID;
1025
}
1026
1027
my_bool STDCALL mysql_eof(MYSQL_RES *res)
1028
{
1029
  return res->eof;
1030
}
1031
1032
MYSQL_FIELD * STDCALL mysql_fetch_field_direct(MYSQL_RES *res,uint fieldnr)
1033
{
1034
  return &(res)->fields[fieldnr];
1035
}
1036
1037
MYSQL_FIELD * STDCALL mysql_fetch_fields(MYSQL_RES *res)
1038
{
1039
  return (res)->fields;
1040
}
1041
1042
MYSQL_ROW_OFFSET STDCALL mysql_row_tell(MYSQL_RES *res)
1043
{
1044
  return res->data_cursor;
1045
}
1046
1047
MYSQL_FIELD_OFFSET STDCALL mysql_field_tell(MYSQL_RES *res)
1048
{
1049
  return (res)->current_field;
1050
}
1051
1052
/* MYSQL */
1053
1054
unsigned int STDCALL mysql_field_count(MYSQL *mysql)
1055
{
1056
  return mysql->field_count;
1057
}
1058
1059
my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql)
1060
{
1061
  return mysql->affected_rows;
1062
}
1063
1064
my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql)
1065
{
1066
  return mysql->insert_id;
1067
}
1068
1069
const char *STDCALL mysql_sqlstate(MYSQL *mysql)
1070
{
1071
  return mysql ? mysql->net.sqlstate : cant_connect_sqlstate;
1072
}
1073
1074
uint STDCALL mysql_warning_count(MYSQL *mysql)
1075
{
1076
  return mysql->warning_count;
1077
}
1078
1079
const char *STDCALL mysql_info(MYSQL *mysql)
1080
{
1081
  return mysql->info;
1082
}
1083
1084
ulong STDCALL mysql_thread_id(MYSQL *mysql)
1085
{
1086
  return (mysql)->thread_id;
1087
}
1088
1089
const char * STDCALL mysql_character_set_name(MYSQL *mysql)
1090
{
1091
  return mysql->charset->csname;
1092
}
1093
1094
void STDCALL mysql_get_character_set_info(MYSQL *mysql, MY_CHARSET_INFO *csinfo)
1095
{
1096
  csinfo->number   = mysql->charset->number;
1097
  csinfo->state    = mysql->charset->state;
1098
  csinfo->csname   = mysql->charset->csname;
1099
  csinfo->name     = mysql->charset->name;
1100
  csinfo->comment  = mysql->charset->comment;
1101
  csinfo->mbminlen = mysql->charset->mbminlen;
1102
  csinfo->mbmaxlen = mysql->charset->mbmaxlen;
1103
1104
  if (mysql->options.charset_dir)
1105
    csinfo->dir = mysql->options.charset_dir;
1106
  else
1107
    csinfo->dir = charsets_dir;
1108
}
1109
1110
uint STDCALL mysql_thread_safe(void)
1111
{
1112
  return 1;
1113
}
1114
1115
1116
my_bool STDCALL mysql_embedded(void)
1117
{
1118
#ifdef EMBEDDED_LIBRARY
1119
  return 1;
1120
#else
1121
  return 0;
1122
#endif
1123
}
1124
1125
/****************************************************************************
1126
  Some support functions
1127
****************************************************************************/
1128
1129
/*
1130
  Functions called my my_net_init() to set some application specific variables
1131
*/
1132
1133
void my_net_local_init(NET *net)
1134
{
1135
  net->max_packet=   (uint) net_buffer_length;
1136
  my_net_set_read_timeout(net, CLIENT_NET_READ_TIMEOUT);
1137
  my_net_set_write_timeout(net, CLIENT_NET_WRITE_TIMEOUT);
1138
  net->retry_count=  1;
1139
  net->max_packet_size= max(net_buffer_length, max_allowed_packet);
1140
}
1141
1142
/*
1143
  This function is used to create HEX string that you
1144
  can use in a SQL statement in of the either ways:
1145
    INSERT INTO blob_column VALUES (0xAABBCC);  (any MySQL version)
1146
    INSERT INTO blob_column VALUES (X'AABBCC'); (4.1 and higher)
1147
  
1148
  The string in "from" is encoded to a HEX string.
1149
  The result is placed in "to" and a terminating null byte is appended.
1150
  
1151
  The string pointed to by "from" must be "length" bytes long.
1152
  You must allocate the "to" buffer to be at least length*2+1 bytes long.
1153
  Each character needs two bytes, and you need room for the terminating
1154
  null byte. When mysql_hex_string() returns, the contents of "to" will
1155
  be a null-terminated string. The return value is the length of the
1156
  encoded string, not including the terminating null character.
1157
1158
  The return value does not contain any leading 0x or a leading X' and
1159
  trailing '. The caller must supply whichever of those is desired.
1160
*/
1161
1162
ulong STDCALL
1163
mysql_hex_string(char *to, const char *from, ulong length)
1164
{
1165
  char *to0= to;
1166
  const char *end;
1167
            
1168
  for (end= from + length; from < end; from++)
1169
  {
1170
    *to++= _dig_vec_upper[((unsigned char) *from) >> 4];
1171
    *to++= _dig_vec_upper[((unsigned char) *from) & 0x0F];
1172
  }
1173
  *to= '\0';
1174
  return (ulong) (to-to0);
1175
}
1176
1177
/*
1178
  Add escape characters to a string (blob?) to make it suitable for a insert
1179
  to should at least have place for length*2+1 chars
1180
  Returns the length of the to string
1181
*/
1182
1183
ulong STDCALL
1184
mysql_escape_string(char *to,const char *from,ulong length)
1185
{
1186
  return escape_string_for_mysql(default_charset_info, to, 0, from, length);
1187
}
1188
1189
ulong STDCALL
1190
mysql_real_escape_string(MYSQL *mysql, char *to,const char *from,
1191
			 ulong length)
1192
{
1193
  if (mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES)
1194
    return escape_quotes_for_mysql(mysql->charset, to, 0, from, length);
1195
  return escape_string_for_mysql(mysql->charset, to, 0, from, length);
1196
}
1197
1198
void STDCALL
1199
myodbc_remove_escape(MYSQL *mysql,char *name)
1200
{
1201
  char *to;
1202
#ifdef USE_MB
1203
  my_bool use_mb_flag=use_mb(mysql->charset);
1204
  char *end;
1205
  if (use_mb_flag)
1206
    for (end=name; *end ; end++) ;
1207
#endif
1208
1209
  for (to=name ; *name ; name++)
1210
  {
1211
#ifdef USE_MB
1212
    int l;
1213
    if (use_mb_flag && (l = my_ismbchar( mysql->charset, name , end ) ) )
1214
    {
1215
      while (l--)
1216
	*to++ = *name++;
1217
      name--;
1218
      continue;
1219
    }
1220
#endif
1221
    if (*name == '\\' && name[1])
1222
      name++;
1223
    *to++= *name;
1224
  }
1225
  *to=0;
1226
}
1227
1228
int cli_unbuffered_fetch(MYSQL *mysql, char **row)
1229
{
1230
  if (packet_error == cli_safe_read(mysql))
1231
    return 1;
1232
1233
  *row= ((mysql->net.read_pos[0] == 254) ? NULL :
1234
	 (char*) (mysql->net.read_pos+1));
1235
  return 0;
1236
}
1237
1238
/********************************************************************
1239
 Transactional APIs
1240
*********************************************************************/
1241
1242
/*
1243
  Commit the current transaction
1244
*/
1245
1246
my_bool STDCALL mysql_commit(MYSQL * mysql)
1247
{
1248
  DBUG_ENTER("mysql_commit");
1249
  DBUG_RETURN((my_bool) mysql_real_query(mysql, "commit", 6));
1250
}
1251
1252
/*
1253
  Rollback the current transaction
1254
*/
1255
1256
my_bool STDCALL mysql_rollback(MYSQL * mysql)
1257
{
1258
  DBUG_ENTER("mysql_rollback");
1259
  DBUG_RETURN((my_bool) mysql_real_query(mysql, "rollback", 8));
1260
}
1261
1262
1263
/*
1264
  Set autocommit to either true or false
1265
*/
1266
1267
my_bool STDCALL mysql_autocommit(MYSQL * mysql, my_bool auto_mode)
1268
{
1269
  DBUG_ENTER("mysql_autocommit");
1270
  DBUG_PRINT("enter", ("mode : %d", auto_mode));
1271
1272
  DBUG_RETURN((my_bool) mysql_real_query(mysql, auto_mode ?
1273
                                         "set autocommit=1":"set autocommit=0",
1274
                                         16));
1275
}
1276
1277
1278
/********************************************************************
1279
 Multi query execution + SPs APIs
1280
*********************************************************************/
1281
1282
/*
1283
  Returns true/false to indicate whether any more query results exist
1284
  to be read using mysql_next_result()
1285
*/
1286
1287
my_bool STDCALL mysql_more_results(MYSQL *mysql)
1288
{
1289
  my_bool res;
1290
  DBUG_ENTER("mysql_more_results");
1291
1292
  res= ((mysql->server_status & SERVER_MORE_RESULTS_EXISTS) ? 1: 0);
1293
  DBUG_PRINT("exit",("More results exists ? %d", res));
1294
  DBUG_RETURN(res);
1295
}
1296
1297
1298
/*
1299
  Reads and returns the next query results
1300
*/
1301
int STDCALL mysql_next_result(MYSQL *mysql)
1302
{
1303
  DBUG_ENTER("mysql_next_result");
1304
1305
  if (mysql->status != MYSQL_STATUS_READY)
1306
  {
1307
    set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
1308
    DBUG_RETURN(1);
1309
  }
1310
1311
  net_clear_error(&mysql->net);
1312
  mysql->affected_rows= ~(my_ulonglong) 0;
1313
1314
  if (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
1315
    DBUG_RETURN((*mysql->methods->next_result)(mysql));
1316
1317
  DBUG_RETURN(-1);				/* No more results */
1318
}
1319
1320
1321
MYSQL_RES * STDCALL mysql_use_result(MYSQL *mysql)
1322
{
1323
  return (*mysql->methods->use_result)(mysql);
1324
}
1325
1326
my_bool STDCALL mysql_read_query_result(MYSQL *mysql)
1327
{
1328
  return (*mysql->methods->read_query_result)(mysql);
1329
}
1330