MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
client.c
1 /* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
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; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 /*
17  This file is included by both libmysql.c (the MySQL client C API)
18  and the mysqld server to connect to another MYSQL server.
19 
20  The differences for the two cases are:
21 
22  - Things that only works for the client:
23  - Trying to automaticly determinate user name if not supplied to
24  mysql_real_connect()
25  - Support for reading local file with LOAD DATA LOCAL
26  - SHARED memory handling
27  - Prepared statements
28  - Things that only works for the server
29 
30  In all other cases, the code should be idential for the client and
31  server.
32 */
33 
34 #include <my_global.h>
35 #include "mysql.h"
36 #include "hash.h"
37 #include "mysql/client_authentication.h"
38 
39 /* Remove client convenience wrappers */
40 #undef max_allowed_packet
41 #undef net_buffer_length
42 
43 #ifdef EMBEDDED_LIBRARY
44 
45 #undef MYSQL_SERVER
46 
47 #ifndef MYSQL_CLIENT
48 #define MYSQL_CLIENT
49 #endif
50 
51 #define CLI_MYSQL_REAL_CONNECT STDCALL cli_mysql_real_connect
52 
53 #undef net_flush
54 my_bool net_flush(NET *net);
55 
56 #else /*EMBEDDED_LIBRARY*/
57 #define CLI_MYSQL_REAL_CONNECT STDCALL mysql_real_connect
58 #endif /*EMBEDDED_LIBRARY*/
59 
60 #include <my_sys.h>
61 #include "my_default.h"
62 #include <mysys_err.h>
63 #include <m_string.h>
64 #include <m_ctype.h>
65 #include "mysql_version.h"
66 #include "mysqld_error.h"
67 #include "errmsg.h"
68 #include <violite.h>
69 
70 #if !defined(__WIN__)
71 #include <my_pthread.h> /* because of signal() */
72 #endif /* !defined(__WIN__) */
73 
74 #include <sys/stat.h>
75 #include <signal.h>
76 #include <time.h>
77 
78 #ifdef HAVE_PWD_H
79 #include <pwd.h>
80 #endif
81 
82 #if !defined(__WIN__)
83 #ifdef HAVE_SELECT_H
84 # include <select.h>
85 #endif
86 #ifdef HAVE_SYS_SELECT_H
87 # include <sys/select.h>
88 #endif
89 #endif /* !defined(__WIN__) */
90 
91 #ifdef HAVE_SYS_UN_H
92 # include <sys/un.h>
93 #endif
94 
95 #ifndef _WIN32
96 #include <errno.h>
97 #define SOCKET_ERROR -1
98 #endif
99 
100 #include "client_settings.h"
101 #include <sql_common.h>
102 #include <mysql/client_plugin.h>
103 
104 #define native_password_plugin_name "mysql_native_password"
105 #define old_password_plugin_name "mysql_old_password"
106 
107 
108 uint mysql_port=0;
109 char *mysql_unix_port= 0;
110 const char *unknown_sqlstate= "HY000";
111 const char *not_error_sqlstate= "00000";
112 const char *cant_connect_sqlstate= "08001";
113 #ifdef HAVE_SMEM
114 char *shared_memory_base_name= 0;
115 const char *def_shared_memory_base_name= default_shared_memory_base_name;
116 #endif
117 
118 static void mysql_close_free_options(MYSQL *mysql);
119 static void mysql_close_free(MYSQL *mysql);
120 static void mysql_prune_stmt_list(MYSQL *mysql);
121 
122 CHARSET_INFO *default_client_charset_info = &my_charset_latin1;
123 
124 /* Server error code and message */
125 unsigned int mysql_server_last_errno;
126 char mysql_server_last_error[MYSQL_ERRMSG_SIZE];
127 
137 static int get_vio_connect_timeout(MYSQL *mysql)
138 {
139  int timeout_ms;
140  uint timeout_sec;
141 
142  /*
143  A timeout of 0 means no timeout. Also, the connect_timeout
144  option value is in seconds, while VIO timeouts are measured
145  in milliseconds. Hence, check for a possible overflow. In
146  case of overflow, set to no timeout.
147  */
148  timeout_sec= mysql->options.connect_timeout;
149 
150  if (!timeout_sec || (timeout_sec > INT_MAX/1000))
151  timeout_ms= -1;
152  else
153  timeout_ms= (int) (timeout_sec * 1000);
154 
155  return timeout_ms;
156 }
157 
158 
159 #ifdef _WIN32
160 
173 static DWORD get_win32_connect_timeout(MYSQL *mysql)
174 {
175  DWORD timeout_ms;
176  uint timeout_sec;
177 
178  /*
179  A timeout of 0 means no timeout. Also, the connect_timeout
180  option value is in seconds, while WIN32 timeouts are in
181  milliseconds. Hence, check for a possible overflow. In case
182  of overflow, set to no timeout.
183  */
184  timeout_sec= mysql->options.connect_timeout;
185 
186  if (!timeout_sec || (timeout_sec > INT_MAX/1000))
187  timeout_ms= INFINITE;
188  else
189  timeout_ms= (DWORD) (timeout_sec * 1000);
190 
191  return timeout_ms;
192 }
193 
194 #endif
195 
196 
206 void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate)
207 {
208  NET *net;
209  DBUG_ENTER("set_mysql_error");
210  DBUG_PRINT("enter", ("error :%d '%s'", errcode, ER(errcode)));
211  DBUG_ASSERT(mysql != 0);
212 
213  if (mysql)
214  {
215  net= &mysql->net;
216  net->last_errno= errcode;
217  strmov(net->last_error, ER(errcode));
218  strmov(net->sqlstate, sqlstate);
219  }
220  else
221  {
222  mysql_server_last_errno= errcode;
223  strmov(mysql_server_last_error, ER(errcode));
224  }
225  DBUG_VOID_RETURN;
226 }
227 
233 my_bool my_net_is_inited(NET *net)
234 {
235  return net->buff != NULL;
236 }
237 
244 void net_clear_error(NET *net)
245 {
246  net->last_errno= 0;
247  net->last_error[0]= '\0';
248  strmov(net->sqlstate, not_error_sqlstate);
249 }
250 
262 void set_mysql_extended_error(MYSQL *mysql, int errcode,
263  const char *sqlstate,
264  const char *format, ...)
265 {
266  NET *net;
267  va_list args;
268  DBUG_ENTER("set_mysql_extended_error");
269  DBUG_PRINT("enter", ("error :%d '%s'", errcode, format));
270  DBUG_ASSERT(mysql != 0);
271 
272  net= &mysql->net;
273  net->last_errno= errcode;
274  va_start(args, format);
275  my_vsnprintf(net->last_error, sizeof(net->last_error)-1,
276  format, args);
277  va_end(args);
278  strmov(net->sqlstate, sqlstate);
279 
280  DBUG_VOID_RETURN;
281 }
282 
283 
284 
285 /*
286  Create a named pipe connection
287 */
288 
289 #ifdef _WIN32
290 
291 static HANDLE create_named_pipe(MYSQL *mysql, DWORD connect_timeout,
292  const char **arg_host,
293  const char **arg_unix_socket)
294 {
295  HANDLE hPipe=INVALID_HANDLE_VALUE;
296  char pipe_name[1024];
297  DWORD dwMode;
298  int i;
299  my_bool testing_named_pipes=0;
300  const char *host= *arg_host, *unix_socket= *arg_unix_socket;
301 
302  if ( ! unix_socket || (unix_socket)[0] == 0x00)
303  unix_socket = mysql_unix_port;
304  if (!host || !strcmp(host,LOCAL_HOST))
305  host=LOCAL_HOST_NAMEDPIPE;
306 
307 
308  pipe_name[sizeof(pipe_name)-1]= 0; /* Safety if too long string */
309  strxnmov(pipe_name, sizeof(pipe_name)-1, "\\\\", host, "\\pipe\\",
310  unix_socket, NullS);
311  DBUG_PRINT("info",("Server name: '%s'. Named Pipe: %s", host, unix_socket));
312 
313  for (i=0 ; i < 100 ; i++) /* Don't retry forever */
314  {
315  if ((hPipe = CreateFile(pipe_name,
316  GENERIC_READ | GENERIC_WRITE,
317  0,
318  NULL,
319  OPEN_EXISTING,
320  FILE_FLAG_OVERLAPPED,
321  NULL )) != INVALID_HANDLE_VALUE)
322  break;
323  if (GetLastError() != ERROR_PIPE_BUSY)
324  {
325  set_mysql_extended_error(mysql, CR_NAMEDPIPEOPEN_ERROR,
326  unknown_sqlstate, ER(CR_NAMEDPIPEOPEN_ERROR),
327  host, unix_socket, (ulong) GetLastError());
328  return INVALID_HANDLE_VALUE;
329  }
330  /* wait for for an other instance */
331  if (!WaitNamedPipe(pipe_name, connect_timeout))
332  {
333  set_mysql_extended_error(mysql, CR_NAMEDPIPEWAIT_ERROR, unknown_sqlstate,
334  ER(CR_NAMEDPIPEWAIT_ERROR),
335  host, unix_socket, (ulong) GetLastError());
336  return INVALID_HANDLE_VALUE;
337  }
338  }
339  if (hPipe == INVALID_HANDLE_VALUE)
340  {
341  set_mysql_extended_error(mysql, CR_NAMEDPIPEOPEN_ERROR, unknown_sqlstate,
342  ER(CR_NAMEDPIPEOPEN_ERROR), host, unix_socket,
343  (ulong) GetLastError());
344  return INVALID_HANDLE_VALUE;
345  }
346  dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
347  if ( !SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL) )
348  {
349  CloseHandle( hPipe );
350  set_mysql_extended_error(mysql, CR_NAMEDPIPESETSTATE_ERROR,
351  unknown_sqlstate, ER(CR_NAMEDPIPESETSTATE_ERROR),
352  host, unix_socket, (ulong) GetLastError());
353  return INVALID_HANDLE_VALUE;
354  }
355  *arg_host=host ; *arg_unix_socket=unix_socket; /* connect arg */
356  return (hPipe);
357 }
358 #endif
359 
360 
361 /*
362  Create new shared memory connection, return handler of connection
363 
364  @param mysql Pointer of mysql structure
365  @param net Pointer of net structure
366  @param connect_timeout Timeout of connection (in milliseconds)
367 
368  @return HANDLE to the shared memory area.
369 */
370 
371 #ifdef HAVE_SMEM
372 static HANDLE create_shared_memory(MYSQL *mysql, NET *net,
373  DWORD connect_timeout)
374 {
375  ulong smem_buffer_length = shared_memory_buffer_length + 4;
376  /*
377  event_connect_request is event object for start connection actions
378  event_connect_answer is event object for confirm, that server put data
379  handle_connect_file_map is file-mapping object, use for create shared
380  memory
381  handle_connect_map is pointer on shared memory
382  handle_map is pointer on shared memory for client
383  event_server_wrote,
384  event_server_read,
385  event_client_wrote,
386  event_client_read are events for transfer data between server and client
387  handle_file_map is file-mapping object, use for create shared memory
388  */
389  HANDLE event_connect_request = NULL;
390  HANDLE event_connect_answer = NULL;
391  HANDLE handle_connect_file_map = NULL;
392  char *handle_connect_map = NULL;
393 
394  char *handle_map = NULL;
395  HANDLE event_server_wrote = NULL;
396  HANDLE event_server_read = NULL;
397  HANDLE event_client_wrote = NULL;
398  HANDLE event_client_read = NULL;
399  HANDLE event_conn_closed = NULL;
400  HANDLE handle_file_map = NULL;
401  ulong connect_number;
402  char connect_number_char[22], *p;
403  char *tmp= NULL;
404  char *suffix_pos;
405  DWORD error_allow = 0;
406  DWORD error_code = 0;
407  DWORD event_access_rights= SYNCHRONIZE | EVENT_MODIFY_STATE;
408  char *shared_memory_base_name = mysql->options.shared_memory_base_name;
409  static const char *name_prefixes[] = {"","Global\\"};
410  const char *prefix;
411  int i;
412 
413  /*
414  If this is NULL, somebody freed the MYSQL* options. mysql_close()
415  is a good candidate. We don't just silently (re)set it to
416  def_shared_memory_base_name as that would create really confusing/buggy
417  behavior if the user passed in a different name on the command-line or
418  in a my.cnf.
419  */
420  DBUG_ASSERT(shared_memory_base_name != NULL);
421 
422  /*
423  get enough space base-name + '_' + longest suffix we might ever send
424  */
425  if (!(tmp= (char *)my_malloc(strlen(shared_memory_base_name) + 32L, MYF(MY_FAE))))
426  goto err;
427 
428  /*
429  The name of event and file-mapping events create agree next rule:
430  shared_memory_base_name+unique_part
431  Where:
432  shared_memory_base_name is unique value for each server
433  unique_part is uniquel value for each object (events and file-mapping)
434  */
435  for (i = 0; i< array_elements(name_prefixes); i++)
436  {
437  prefix= name_prefixes[i];
438  suffix_pos = strxmov(tmp, prefix , shared_memory_base_name, "_", NullS);
439  strmov(suffix_pos, "CONNECT_REQUEST");
440  event_connect_request= OpenEvent(event_access_rights, FALSE, tmp);
441  if (event_connect_request)
442  {
443  break;
444  }
445  }
446  if (!event_connect_request)
447  {
448  error_allow = CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR;
449  goto err;
450  }
451  strmov(suffix_pos, "CONNECT_ANSWER");
452  if (!(event_connect_answer= OpenEvent(event_access_rights,FALSE,tmp)))
453  {
454  error_allow = CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR;
455  goto err;
456  }
457  strmov(suffix_pos, "CONNECT_DATA");
458  if (!(handle_connect_file_map= OpenFileMapping(FILE_MAP_WRITE,FALSE,tmp)))
459  {
460  error_allow = CR_SHARED_MEMORY_CONNECT_FILE_MAP_ERROR;
461  goto err;
462  }
463  if (!(handle_connect_map= MapViewOfFile(handle_connect_file_map,
464  FILE_MAP_WRITE,0,0,sizeof(DWORD))))
465  {
466  error_allow = CR_SHARED_MEMORY_CONNECT_MAP_ERROR;
467  goto err;
468  }
469 
470  /* Send to server request of connection */
471  if (!SetEvent(event_connect_request))
472  {
473  error_allow = CR_SHARED_MEMORY_CONNECT_SET_ERROR;
474  goto err;
475  }
476 
477  /* Wait of answer from server */
478  if (WaitForSingleObject(event_connect_answer, connect_timeout) !=
479  WAIT_OBJECT_0)
480  {
481  error_allow = CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR;
482  goto err;
483  }
484 
485  /* Get number of connection */
486  connect_number = uint4korr(handle_connect_map);/*WAX2*/
487  p= int10_to_str(connect_number, connect_number_char, 10);
488 
489  /*
490  The name of event and file-mapping events create agree next rule:
491  shared_memory_base_name+unique_part+number_of_connection
492 
493  Where:
494  shared_memory_base_name is uniquel value for each server
495  unique_part is uniquel value for each object (events and file-mapping)
496  number_of_connection is number of connection between server and client
497  */
498  suffix_pos = strxmov(tmp, prefix , shared_memory_base_name, "_", connect_number_char,
499  "_", NullS);
500  strmov(suffix_pos, "DATA");
501  if ((handle_file_map = OpenFileMapping(FILE_MAP_WRITE,FALSE,tmp)) == NULL)
502  {
503  error_allow = CR_SHARED_MEMORY_FILE_MAP_ERROR;
504  goto err2;
505  }
506  if ((handle_map = MapViewOfFile(handle_file_map,FILE_MAP_WRITE,0,0,
507  smem_buffer_length)) == NULL)
508  {
509  error_allow = CR_SHARED_MEMORY_MAP_ERROR;
510  goto err2;
511  }
512 
513  strmov(suffix_pos, "SERVER_WROTE");
514  if ((event_server_wrote = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
515  {
516  error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
517  goto err2;
518  }
519 
520  strmov(suffix_pos, "SERVER_READ");
521  if ((event_server_read = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
522  {
523  error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
524  goto err2;
525  }
526 
527  strmov(suffix_pos, "CLIENT_WROTE");
528  if ((event_client_wrote = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
529  {
530  error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
531  goto err2;
532  }
533 
534  strmov(suffix_pos, "CLIENT_READ");
535  if ((event_client_read = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
536  {
537  error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
538  goto err2;
539  }
540 
541  strmov(suffix_pos, "CONNECTION_CLOSED");
542  if ((event_conn_closed = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
543  {
544  error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
545  goto err2;
546  }
547  /*
548  Set event that server should send data
549  */
550  SetEvent(event_server_read);
551 
552 err2:
553  if (error_allow == 0)
554  {
555  net->vio= vio_new_win32shared_memory(handle_file_map,handle_map,
556  event_server_wrote,
557  event_server_read,event_client_wrote,
558  event_client_read,event_conn_closed);
559  }
560  else
561  {
562  error_code = GetLastError();
563  if (event_server_read)
564  CloseHandle(event_server_read);
565  if (event_server_wrote)
566  CloseHandle(event_server_wrote);
567  if (event_client_read)
568  CloseHandle(event_client_read);
569  if (event_client_wrote)
570  CloseHandle(event_client_wrote);
571  if (event_conn_closed)
572  CloseHandle(event_conn_closed);
573  if (handle_map)
574  UnmapViewOfFile(handle_map);
575  if (handle_file_map)
576  CloseHandle(handle_file_map);
577  }
578 err:
579  my_free(tmp);
580  if (error_allow)
581  error_code = GetLastError();
582  if (event_connect_request)
583  CloseHandle(event_connect_request);
584  if (event_connect_answer)
585  CloseHandle(event_connect_answer);
586  if (handle_connect_map)
587  UnmapViewOfFile(handle_connect_map);
588  if (handle_connect_file_map)
589  CloseHandle(handle_connect_file_map);
590  if (error_allow)
591  {
592  if (error_allow == CR_SHARED_MEMORY_EVENT_ERROR)
593  set_mysql_extended_error(mysql, error_allow, unknown_sqlstate,
594  ER(error_allow), suffix_pos, error_code);
595  else
596  set_mysql_extended_error(mysql, error_allow, unknown_sqlstate,
597  ER(error_allow), error_code);
598  return(INVALID_HANDLE_VALUE);
599  }
600  return(handle_map);
601 }
602 #endif
603 
613 ulong
614 cli_safe_read(MYSQL *mysql)
615 {
616  NET *net= &mysql->net;
617  ulong len=0;
618 
619  if (net->vio != 0)
620  len=my_net_read(net);
621 
622  if (len == packet_error || len == 0)
623  {
624  DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %lu",
625  vio_description(net->vio),len));
626 #ifdef MYSQL_SERVER
627  if (net->vio && (net->last_errno == ER_NET_READ_INTERRUPTED))
628  return (packet_error);
629 #endif /*MYSQL_SERVER*/
630  end_server(mysql);
631  set_mysql_error(mysql, net->last_errno == ER_NET_PACKET_TOO_LARGE ?
632  CR_NET_PACKET_TOO_LARGE: CR_SERVER_LOST, unknown_sqlstate);
633  return (packet_error);
634  }
635  if (net->read_pos[0] == 255)
636  {
637  if (len > 3)
638  {
639  char *pos=(char*) net->read_pos+1;
640  net->last_errno=uint2korr(pos);
641  pos+=2;
642  len-=2;
643  if (protocol_41(mysql) && pos[0] == '#')
644  {
645  strmake(net->sqlstate, pos+1, SQLSTATE_LENGTH);
646  pos+= SQLSTATE_LENGTH+1;
647  }
648  else
649  {
650  /*
651  The SQL state hasn't been received -- it should be reset to HY000
652  (unknown error sql state).
653  */
654 
655  strmov(net->sqlstate, unknown_sqlstate);
656  }
657 
658  (void) strmake(net->last_error,(char*) pos,
659  MY_MIN((uint) len,(uint) sizeof(net->last_error)-1));
660  }
661  else
662  set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
663  /*
664  Cover a protocol design error: error packet does not
665  contain the server status. Therefore, the client has no way
666  to find out whether there are more result sets of
667  a multiple-result-set statement pending. Luckily, in 5.0 an
668  error always aborts execution of a statement, wherever it is
669  a multi-statement or a stored procedure, so it should be
670  safe to unconditionally turn off the flag here.
671  */
672  mysql->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
673 
674  DBUG_PRINT("error",("Got error: %d/%s (%s)",
675  net->last_errno,
676  net->sqlstate,
677  net->last_error));
678  return(packet_error);
679  }
680  return len;
681 }
682 
683 void free_rows(MYSQL_DATA *cur)
684 {
685  if (cur)
686  {
687  free_root(&cur->alloc,MYF(0));
688  my_free(cur);
689  }
690 }
691 
692 my_bool
693 cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
694  const uchar *header, ulong header_length,
695  const uchar *arg, ulong arg_length, my_bool skip_check,
696  MYSQL_STMT *stmt)
697 {
698  NET *net= &mysql->net;
699  my_bool result= 1;
700  my_bool stmt_skip= stmt ? stmt->state != MYSQL_STMT_INIT_DONE : FALSE;
701  DBUG_ENTER("cli_advanced_command");
702 
703  if (mysql->net.vio == 0)
704  { /* Do reconnect if possible */
705  if (mysql_reconnect(mysql) || stmt_skip)
706  DBUG_RETURN(1);
707  }
708  if (mysql->status != MYSQL_STATUS_READY ||
709  mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
710  {
711  DBUG_PRINT("error",("state: %d", mysql->status));
712  set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
713  DBUG_RETURN(1);
714  }
715 
716  net_clear_error(net);
717  mysql->info=0;
718  mysql->affected_rows= ~(my_ulonglong) 0;
719  /*
720  Do not check the socket/protocol buffer on COM_QUIT as the
721  result of a previous command might not have been read. This
722  can happen if a client sends a query but does not reap the
723  result before attempting to close the connection.
724  */
725  net_clear(&mysql->net, (command != COM_QUIT));
726 
727  if (net_write_command(net,(uchar) command, header, header_length,
728  arg, arg_length))
729  {
730  DBUG_PRINT("error",("Can't send command to server. Error: %d",
731  socket_errno));
732  if (net->last_errno == ER_NET_PACKET_TOO_LARGE)
733  {
734  set_mysql_error(mysql, CR_NET_PACKET_TOO_LARGE, unknown_sqlstate);
735  goto end;
736  }
737  end_server(mysql);
738  if (mysql_reconnect(mysql) || stmt_skip)
739  goto end;
740  if (net_write_command(net,(uchar) command, header, header_length,
741  arg, arg_length))
742  {
743  set_mysql_error(mysql, CR_SERVER_GONE_ERROR, unknown_sqlstate);
744  goto end;
745  }
746  }
747  result=0;
748  if (!skip_check)
749  result= ((mysql->packet_length=cli_safe_read(mysql)) == packet_error ?
750  1 : 0);
751 end:
752  DBUG_PRINT("exit",("result: %d", result));
753  DBUG_RETURN(result);
754 }
755 
756 void free_old_query(MYSQL *mysql)
757 {
758  DBUG_ENTER("free_old_query");
759  if (mysql->fields)
760  free_root(&mysql->field_alloc,MYF(0));
761  init_alloc_root(&mysql->field_alloc,8192,0); /* Assume rowlength < 8192 */
762  mysql->fields= 0;
763  mysql->field_count= 0; /* For API */
764  mysql->warning_count= 0;
765  mysql->info= 0;
766  DBUG_VOID_RETURN;
767 }
768 
769 
779 my_bool flush_one_result(MYSQL *mysql)
780 {
781  ulong packet_length;
782 
783  DBUG_ASSERT(mysql->status != MYSQL_STATUS_READY);
784 
785  do
786  {
787  packet_length= cli_safe_read(mysql);
788  /*
789  There is an error reading from the connection,
790  or (sic!) there were no error and no
791  data in the stream, i.e. no more data from the server.
792  Since we know our position in the stream (somewhere in
793  the middle of a result set), this latter case is an error too
794  -- each result set must end with a EOF packet.
795  cli_safe_read() has set an error for us, just return.
796  */
797  if (packet_length == packet_error)
798  return TRUE;
799  }
800  while (packet_length > 8 || mysql->net.read_pos[0] != 254);
801 
802  /* Analyze EOF packet of the result set. */
803 
804  if (protocol_41(mysql))
805  {
806  char *pos= (char*) mysql->net.read_pos + 1;
807  mysql->warning_count=uint2korr(pos);
808  pos+=2;
809  mysql->server_status=uint2korr(pos);
810  pos+=2;
811  }
812  return FALSE;
813 }
814 
815 
824 my_bool opt_flush_ok_packet(MYSQL *mysql, my_bool *is_ok_packet)
825 {
826  ulong packet_length= cli_safe_read(mysql);
827 
828  if (packet_length == packet_error)
829  return TRUE;
830 
831  /* cli_safe_read always reads a non-empty packet. */
832  DBUG_ASSERT(packet_length);
833 
834  *is_ok_packet= mysql->net.read_pos[0] == 0;
835  if (*is_ok_packet)
836  {
837  uchar *pos= mysql->net.read_pos + 1;
838 
839  net_field_length_ll(&pos); /* affected rows */
840  net_field_length_ll(&pos); /* insert id */
841 
842  mysql->server_status=uint2korr(pos);
843  pos+=2;
844 
845  if (protocol_41(mysql))
846  {
847  mysql->warning_count=uint2korr(pos);
848  pos+=2;
849  }
850  }
851  return FALSE;
852 }
853 
854 
855 /*
856  Flush result set sent from server
857 */
858 
859 static void cli_flush_use_result(MYSQL *mysql, my_bool flush_all_results)
860 {
861  /* Clear the current execution status */
862  DBUG_ENTER("cli_flush_use_result");
863  DBUG_PRINT("warning",("Not all packets read, clearing them"));
864 
865  if (flush_one_result(mysql))
866  DBUG_VOID_RETURN; /* An error occurred */
867 
868  if (! flush_all_results)
869  DBUG_VOID_RETURN;
870 
871  while (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
872  {
873  my_bool is_ok_packet;
874  if (opt_flush_ok_packet(mysql, &is_ok_packet))
875  DBUG_VOID_RETURN; /* An error occurred. */
876  if (is_ok_packet)
877  {
878  /*
879  Indeed what we got from network was an OK packet, and we
880  know that OK is the last one in a multi-result-set, so
881  just return.
882  */
883  DBUG_VOID_RETURN;
884  }
885  /*
886  It's a result set, not an OK packet. A result set contains
887  of two result set subsequences: field metadata, terminated
888  with EOF packet, and result set data, again terminated with
889  EOF packet. Read and flush them.
890  */
891  if (flush_one_result(mysql) || flush_one_result(mysql))
892  DBUG_VOID_RETURN; /* An error occurred. */
893  }
894 
895  DBUG_VOID_RETURN;
896 }
897 
898 
899 #ifdef __WIN__
900 static my_bool is_NT(void)
901 {
902  char *os=getenv("OS");
903  return (os && !strcmp(os, "Windows_NT")) ? 1 : 0;
904 }
905 #endif
906 
907 
908 #ifdef CHECK_LICENSE
909 
920 static int check_license(MYSQL *mysql)
921 {
922  MYSQL_ROW row;
923  MYSQL_RES *res;
924  NET *net= &mysql->net;
925  static const char query[]= "SELECT @@license";
926  static const char required_license[]= STRINGIFY_ARG(LICENSE);
927 
928  if (mysql_real_query(mysql, query, sizeof(query)-1))
929  {
930  if (net->last_errno == ER_UNKNOWN_SYSTEM_VARIABLE)
931  {
932  set_mysql_extended_error(mysql, CR_WRONG_LICENSE, unknown_sqlstate,
933  ER(CR_WRONG_LICENSE), required_license);
934  }
935  return 1;
936  }
937  if (!(res= mysql_use_result(mysql)))
938  return 1;
939  row= mysql_fetch_row(res);
940  /*
941  If no rows in result set, or column value is NULL (none of these
942  two is ever true for server variables now), or column value
943  mismatch, set wrong license error.
944  */
945  if (!net->last_errno &&
946  (!row || !row[0] ||
947  strncmp(row[0], required_license, sizeof(required_license))))
948  {
949  set_mysql_extended_error(mysql, CR_WRONG_LICENSE, unknown_sqlstate,
950  ER(CR_WRONG_LICENSE), required_license);
951  }
952  mysql_free_result(res);
953  return net->last_errno;
954 }
955 #endif /* CHECK_LICENSE */
956 
957 
958 /**************************************************************************
959  Shut down connection
960 **************************************************************************/
961 
962 void end_server(MYSQL *mysql)
963 {
964  int save_errno= errno;
965  DBUG_ENTER("end_server");
966  if (mysql->net.vio != 0)
967  {
968  DBUG_PRINT("info",("Net: %s", vio_description(mysql->net.vio)));
969 #ifdef MYSQL_SERVER
970  slave_io_thread_detach_vio();
971 #endif
972  vio_delete(mysql->net.vio);
973  mysql->net.vio= 0; /* Marker */
974  mysql_prune_stmt_list(mysql);
975  }
976  net_end(&mysql->net);
977  free_old_query(mysql);
978  errno= save_errno;
979  DBUG_VOID_RETURN;
980 }
981 
982 
983 void STDCALL
984 mysql_free_result(MYSQL_RES *result)
985 {
986  DBUG_ENTER("mysql_free_result");
987  DBUG_PRINT("enter",("mysql_res: 0x%lx", (long) result));
988  if (result)
989  {
990  MYSQL *mysql= result->handle;
991  if (mysql)
992  {
993  if (mysql->unbuffered_fetch_owner == &result->unbuffered_fetch_cancelled)
994  mysql->unbuffered_fetch_owner= 0;
995  if (mysql->status == MYSQL_STATUS_USE_RESULT)
996  {
997  (*mysql->methods->flush_use_result)(mysql, FALSE);
998  mysql->status=MYSQL_STATUS_READY;
999  if (mysql->unbuffered_fetch_owner)
1000  *mysql->unbuffered_fetch_owner= TRUE;
1001  }
1002  }
1003  free_rows(result->data);
1004  if (result->fields)
1005  free_root(&result->field_alloc,MYF(0));
1006  my_free(result->row);
1007  my_free(result);
1008  }
1009  DBUG_VOID_RETURN;
1010 }
1011 
1012 /****************************************************************************
1013  Get options from my.cnf
1014 ****************************************************************************/
1015 
1016 static const char *default_options[]=
1017 {
1018  "port","socket","compress","password","pipe", "timeout", "user",
1019  "init-command", "host", "database", "debug", "return-found-rows",
1020  "ssl-key" ,"ssl-cert" ,"ssl-ca" ,"ssl-capath",
1021  "character-sets-dir", "default-character-set", "interactive-timeout",
1022  "connect-timeout", "local-infile", "disable-local-infile",
1023  "ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name",
1024  "multi-results", "multi-statements", "multi-queries", "secure-auth",
1025  "report-data-truncation", "plugin-dir", "default-auth",
1026  "bind-address", "ssl-crl", "ssl-crlpath", "enable-cleartext-plugin",
1027  NullS
1028 };
1029 enum option_id {
1030  OPT_port=1, OPT_socket, OPT_compress, OPT_password, OPT_pipe, OPT_timeout, OPT_user,
1031  OPT_init_command, OPT_host, OPT_database, OPT_debug, OPT_return_found_rows,
1032  OPT_ssl_key, OPT_ssl_cert, OPT_ssl_ca, OPT_ssl_capath,
1033  OPT_character_sets_dir, OPT_default_character_set, OPT_interactive_timeout,
1034  OPT_connect_timeout, OPT_local_infile, OPT_disable_local_infile,
1035  OPT_ssl_cipher, OPT_max_allowed_packet, OPT_protocol, OPT_shared_memory_base_name,
1036  OPT_multi_results, OPT_multi_statements, OPT_multi_queries, OPT_secure_auth,
1037  OPT_report_data_truncation, OPT_plugin_dir, OPT_default_auth,
1038  OPT_bind_address, OPT_ssl_crl, OPT_ssl_crlpath, OPT_enable_cleartext_plugin,
1039  OPT_keep_this_one_last
1040 };
1041 
1042 static TYPELIB option_types={array_elements(default_options)-1,
1043  "options",default_options, NULL};
1044 
1045 const char *sql_protocol_names_lib[] =
1046 { "TCP", "SOCKET", "PIPE", "MEMORY", NullS };
1047 TYPELIB sql_protocol_typelib = {array_elements(sql_protocol_names_lib)-1,"",
1048  sql_protocol_names_lib, NULL};
1049 
1050 static int add_init_command(struct st_mysql_options *options, const char *cmd)
1051 {
1052  char *tmp;
1053 
1054  if (!options->init_commands)
1055  {
1056  options->init_commands= (DYNAMIC_ARRAY*)my_malloc(sizeof(DYNAMIC_ARRAY),
1057  MYF(MY_WME));
1058  init_dynamic_array(options->init_commands,sizeof(char*),0,5);
1059  }
1060 
1061  if (!(tmp= my_strdup(cmd,MYF(MY_WME))) ||
1062  insert_dynamic(options->init_commands, &tmp))
1063  {
1064  my_free(tmp);
1065  return 1;
1066  }
1067 
1068  return 0;
1069 }
1070 
1071 #define ALLOCATE_EXTENSIONS(OPTS) \
1072  (OPTS)->extension= (struct st_mysql_options_extention *) \
1073  my_malloc(sizeof(struct st_mysql_options_extention), \
1074  MYF(MY_WME | MY_ZEROFILL)) \
1075 
1076 #define ENSURE_EXTENSIONS_PRESENT(OPTS) \
1077  do { \
1078  if (!(OPTS)->extension) \
1079  ALLOCATE_EXTENSIONS(OPTS); \
1080  } while (0)
1081 
1082 
1083 #define EXTENSION_SET_STRING(OPTS, X, STR) \
1084  do { \
1085  if ((OPTS)->extension) \
1086  my_free((OPTS)->extension->X); \
1087  else \
1088  ALLOCATE_EXTENSIONS(OPTS); \
1089  (OPTS)->extension->X= ((STR) != NULL) ? \
1090  my_strdup((STR), MYF(MY_WME)) : NULL; \
1091  } while (0)
1092 
1093 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
1094 #define SET_SSL_OPTION(opt_var,arg) \
1095  if (mysql->options.opt_var) \
1096  my_free(mysql->options.opt_var); \
1097  mysql->options.opt_var= arg ? my_strdup(arg, MYF(MY_WME)) : NULL; \
1098  if (mysql->options.opt_var) \
1099  mysql->options.use_ssl= 1
1100 #define EXTENSION_SET_SSL_STRING(OPTS, X, STR) \
1101  EXTENSION_SET_STRING(OPTS, X, STR); \
1102  if ((OPTS)->extension->X) \
1103  (OPTS)->use_ssl= 1
1104 
1105 
1106 #else
1107 #define SET_SSL_OPTION(opt_var,arg) \
1108  do { \
1109  ; \
1110  } while(0)
1111 #define EXTENSION_SET_SSL_STRING(OPTS, X, STR) \
1112  do { \
1113  ; \
1114  } while(0)
1115 #endif
1116 
1117 void mysql_read_default_options(struct st_mysql_options *options,
1118  const char *filename,const char *group)
1119 {
1120  int argc;
1121  char *argv_buff[1],**argv;
1122  const char *groups[3];
1123  DBUG_ENTER("mysql_read_default_options");
1124  DBUG_PRINT("enter",("file: %s group: %s",filename,group ? group :"NULL"));
1125 
1126  compile_time_assert(OPT_keep_this_one_last ==
1127  array_elements(default_options));
1128 
1129  argc=1; argv=argv_buff; argv_buff[0]= (char*) "client";
1130  groups[0]= (char*) "client"; groups[1]= (char*) group; groups[2]=0;
1131 
1132  my_load_defaults(filename, groups, &argc, &argv, NULL);
1133  if (argc != 1) /* If some default option */
1134  {
1135  char **option=argv;
1136  while (*++option)
1137  {
1138  if (my_getopt_is_args_separator(option[0])) /* skip arguments separator */
1139  continue;
1140  /* DBUG_PRINT("info",("option: %s",option[0])); */
1141  if (option[0][0] == '-' && option[0][1] == '-')
1142  {
1143  char *end=strcend(*option,'=');
1144  char *opt_arg=0;
1145  if (*end)
1146  {
1147  opt_arg=end+1;
1148  *end=0; /* Remove '=' */
1149  }
1150  /* Change all '_' in variable name to '-' */
1151  for (end= *option ; *(end= strcend(end,'_')) ; )
1152  *end= '-';
1153  switch (find_type(*option + 2, &option_types, FIND_TYPE_BASIC)) {
1154  case OPT_port:
1155  if (opt_arg)
1156  options->port=atoi(opt_arg);
1157  break;
1158  case OPT_socket:
1159  if (opt_arg)
1160  {
1161  my_free(options->unix_socket);
1162  options->unix_socket=my_strdup(opt_arg,MYF(MY_WME));
1163  }
1164  break;
1165  case OPT_compress:
1166  options->compress=1;
1167  options->client_flag|= CLIENT_COMPRESS;
1168  break;
1169  case OPT_password:
1170  if (opt_arg)
1171  {
1172  my_free(options->password);
1173  options->password=my_strdup(opt_arg,MYF(MY_WME));
1174  }
1175  break;
1176  case OPT_pipe:
1177  options->protocol = MYSQL_PROTOCOL_PIPE;
1178  case OPT_connect_timeout:
1179  case OPT_timeout:
1180  if (opt_arg)
1181  options->connect_timeout=atoi(opt_arg);
1182  break;
1183  case OPT_user:
1184  if (opt_arg)
1185  {
1186  my_free(options->user);
1187  options->user=my_strdup(opt_arg,MYF(MY_WME));
1188  }
1189  break;
1190  case OPT_init_command:
1191  add_init_command(options,opt_arg);
1192  break;
1193  case OPT_host:
1194  if (opt_arg)
1195  {
1196  my_free(options->host);
1197  options->host=my_strdup(opt_arg,MYF(MY_WME));
1198  }
1199  break;
1200  case OPT_database:
1201  if (opt_arg)
1202  {
1203  my_free(options->db);
1204  options->db=my_strdup(opt_arg,MYF(MY_WME));
1205  }
1206  break;
1207  case OPT_debug:
1208 #ifdef MYSQL_CLIENT
1209  mysql_debug(opt_arg ? opt_arg : "d:t:o,/tmp/client.trace");
1210  break;
1211 #endif
1212  case OPT_return_found_rows:
1213  options->client_flag|=CLIENT_FOUND_ROWS;
1214  break;
1215 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
1216  case OPT_ssl_key:
1217  my_free(options->ssl_key);
1218  options->ssl_key = my_strdup(opt_arg, MYF(MY_WME));
1219  break;
1220  case OPT_ssl_cert:
1221  my_free(options->ssl_cert);
1222  options->ssl_cert = my_strdup(opt_arg, MYF(MY_WME));
1223  break;
1224  case OPT_ssl_ca:
1225  my_free(options->ssl_ca);
1226  options->ssl_ca = my_strdup(opt_arg, MYF(MY_WME));
1227  break;
1228  case OPT_ssl_capath:
1229  my_free(options->ssl_capath);
1230  options->ssl_capath = my_strdup(opt_arg, MYF(MY_WME));
1231  break;
1232  case OPT_ssl_cipher:
1233  my_free(options->ssl_cipher);
1234  options->ssl_cipher= my_strdup(opt_arg, MYF(MY_WME));
1235  break;
1236  case OPT_ssl_crl:
1237  EXTENSION_SET_SSL_STRING(options, ssl_crl, opt_arg);
1238  break;
1239  case OPT_ssl_crlpath:
1240  EXTENSION_SET_SSL_STRING(options, ssl_crlpath, opt_arg);
1241  break;
1242 #else
1243  case OPT_ssl_key:
1244  case OPT_ssl_cert:
1245  case OPT_ssl_ca:
1246  case OPT_ssl_capath:
1247  case OPT_ssl_cipher:
1248  case OPT_ssl_crl:
1249  case OPT_ssl_crlpath:
1250  break;
1251 #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
1252  case OPT_character_sets_dir:
1253  my_free(options->charset_dir);
1254  options->charset_dir = my_strdup(opt_arg, MYF(MY_WME));
1255  break;
1256  case OPT_default_character_set:
1257  my_free(options->charset_name);
1258  options->charset_name = my_strdup(opt_arg, MYF(MY_WME));
1259  break;
1260  case OPT_interactive_timeout:
1261  options->client_flag|= CLIENT_INTERACTIVE;
1262  break;
1263  case OPT_local_infile:
1264  if (!opt_arg || atoi(opt_arg) != 0)
1265  options->client_flag|= CLIENT_LOCAL_FILES;
1266  else
1267  options->client_flag&= ~CLIENT_LOCAL_FILES;
1268  break;
1269  case OPT_disable_local_infile:
1270  options->client_flag&= ~CLIENT_LOCAL_FILES;
1271  break;
1272  case OPT_max_allowed_packet:
1273  if (opt_arg)
1274  options->max_allowed_packet= atoi(opt_arg);
1275  break;
1276  case OPT_protocol:
1277  if ((options->protocol= find_type(opt_arg, &sql_protocol_typelib,
1278  FIND_TYPE_BASIC)) <= 0)
1279  {
1280  fprintf(stderr, "Unknown option to protocol: %s\n", opt_arg);
1281  exit(1);
1282  }
1283  break;
1284  case OPT_shared_memory_base_name:
1285 #ifdef HAVE_SMEM
1286  if (options->shared_memory_base_name != def_shared_memory_base_name)
1287  my_free(options->shared_memory_base_name);
1288  options->shared_memory_base_name=my_strdup(opt_arg,MYF(MY_WME));
1289 #endif
1290  break;
1291  case OPT_multi_results:
1292  options->client_flag|= CLIENT_MULTI_RESULTS;
1293  break;
1294  case OPT_multi_statements:
1295  case OPT_multi_queries:
1296  options->client_flag|= CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS;
1297  break;
1298  case OPT_secure_auth:
1299  options->secure_auth= TRUE;
1300  break;
1301  case OPT_report_data_truncation:
1302  options->report_data_truncation= opt_arg ? test(atoi(opt_arg)) : 1;
1303  break;
1304  case OPT_plugin_dir:
1305  {
1306  char buff[FN_REFLEN], buff2[FN_REFLEN];
1307  if (strlen(opt_arg) >= FN_REFLEN)
1308  opt_arg[FN_REFLEN]= '\0';
1309  if (my_realpath(buff, opt_arg, 0))
1310  {
1311  DBUG_PRINT("warning",("failed to normalize the plugin path: %s",
1312  opt_arg));
1313  break;
1314  }
1315  convert_dirname(buff2, buff, NULL);
1316  EXTENSION_SET_STRING(options, plugin_dir, buff2);
1317  }
1318  break;
1319  case OPT_default_auth:
1320  EXTENSION_SET_STRING(options, default_auth, opt_arg);
1321  break;
1322  case OPT_bind_address:
1323  my_free(options->ci.bind_address);
1324  options->ci.bind_address= my_strdup(opt_arg, MYF(MY_WME));
1325  break;
1326  case OPT_enable_cleartext_plugin:
1327  ENSURE_EXTENSIONS_PRESENT(options);
1328  options->extension->enable_cleartext_plugin=
1329  (!opt_arg || atoi(opt_arg) != 0) ? TRUE : FALSE;
1330  break;
1331 
1332  default:
1333  DBUG_PRINT("warning",("unknown option: %s",option[0]));
1334  }
1335  }
1336  }
1337  }
1338  free_defaults(argv);
1339  DBUG_VOID_RETURN;
1340 }
1341 
1342 
1343 /**************************************************************************
1344  Get column lengths of the current row
1345  If one uses mysql_use_result, res->lengths contains the length information,
1346  else the lengths are calculated from the offset between pointers.
1347 **************************************************************************/
1348 
1349 static void cli_fetch_lengths(ulong *to, MYSQL_ROW column,
1350  unsigned int field_count)
1351 {
1352  ulong *prev_length;
1353  char *start=0;
1354  MYSQL_ROW end;
1355 
1356  prev_length=0; /* Keep gcc happy */
1357  for (end=column + field_count + 1 ; column != end ; column++, to++)
1358  {
1359  if (!*column)
1360  {
1361  *to= 0; /* Null */
1362  continue;
1363  }
1364  if (start) /* Found end of prev string */
1365  *prev_length= (ulong) (*column-start-1);
1366  start= *column;
1367  prev_length= to;
1368  }
1369 }
1370 
1371 /***************************************************************************
1372  Change field rows to field structs
1373 ***************************************************************************/
1374 
1375 MYSQL_FIELD *
1376 unpack_fields(MYSQL *mysql, MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
1377  my_bool default_value, uint server_capabilities)
1378 {
1379  MYSQL_ROWS *row;
1380  MYSQL_FIELD *field,*result;
1381  ulong lengths[9]; /* Max of fields */
1382  DBUG_ENTER("unpack_fields");
1383 
1384  field= result= (MYSQL_FIELD*) alloc_root(alloc,
1385  (uint) sizeof(*field)*fields);
1386  if (!result)
1387  {
1388  free_rows(data); /* Free old data */
1389  set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
1390  DBUG_RETURN(0);
1391  }
1392  memset(field, 0, sizeof(MYSQL_FIELD)*fields);
1393  if (server_capabilities & CLIENT_PROTOCOL_41)
1394  {
1395  /* server is 4.1, and returns the new field result format */
1396  for (row=data->data; row ; row = row->next,field++)
1397  {
1398  uchar *pos;
1399  /* fields count may be wrong */
1400  DBUG_ASSERT((uint) (field - result) < fields);
1401  cli_fetch_lengths(&lengths[0], row->data, default_value ? 8 : 7);
1402  field->catalog= strmake_root(alloc,(char*) row->data[0], lengths[0]);
1403  field->db= strmake_root(alloc,(char*) row->data[1], lengths[1]);
1404  field->table= strmake_root(alloc,(char*) row->data[2], lengths[2]);
1405  field->org_table= strmake_root(alloc,(char*) row->data[3], lengths[3]);
1406  field->name= strmake_root(alloc,(char*) row->data[4], lengths[4]);
1407  field->org_name= strmake_root(alloc,(char*) row->data[5], lengths[5]);
1408 
1409  field->catalog_length= lengths[0];
1410  field->db_length= lengths[1];
1411  field->table_length= lengths[2];
1412  field->org_table_length= lengths[3];
1413  field->name_length= lengths[4];
1414  field->org_name_length= lengths[5];
1415 
1416  /* Unpack fixed length parts */
1417  if (lengths[6] != 12)
1418  {
1419  /* malformed packet. signal an error. */
1420  free_rows(data); /* Free old data */
1421  set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
1422  DBUG_RETURN(0);
1423  }
1424 
1425  pos= (uchar*) row->data[6];
1426  field->charsetnr= uint2korr(pos);
1427  field->length= (uint) uint4korr(pos+2);
1428  field->type= (enum enum_field_types) pos[6];
1429  field->flags= uint2korr(pos+7);
1430  field->decimals= (uint) pos[9];
1431 
1432  if (IS_NUM(field->type))
1433  field->flags|= NUM_FLAG;
1434  if (default_value && row->data[7])
1435  {
1436  field->def=strmake_root(alloc,(char*) row->data[7], lengths[7]);
1437  field->def_length= lengths[7];
1438  }
1439  else
1440  field->def=0;
1441  field->max_length= 0;
1442  }
1443  }
1444 #ifndef DELETE_SUPPORT_OF_4_0_PROTOCOL
1445  else
1446  {
1447  /* old protocol, for backward compatibility */
1448  for (row=data->data; row ; row = row->next,field++)
1449  {
1450  cli_fetch_lengths(&lengths[0], row->data, default_value ? 6 : 5);
1451  field->org_table= field->table= strdup_root(alloc,(char*) row->data[0]);
1452  field->name= strdup_root(alloc,(char*) row->data[1]);
1453  field->length= (uint) uint3korr(row->data[2]);
1454  field->type= (enum enum_field_types) (uchar) row->data[3][0];
1455 
1456  field->catalog=(char*) "";
1457  field->db= (char*) "";
1458  field->catalog_length= 0;
1459  field->db_length= 0;
1460  field->org_table_length= field->table_length= lengths[0];
1461  field->name_length= lengths[1];
1462 
1463  if (server_capabilities & CLIENT_LONG_FLAG)
1464  {
1465  field->flags= uint2korr(row->data[4]);
1466  field->decimals=(uint) (uchar) row->data[4][2];
1467  }
1468  else
1469  {
1470  field->flags= (uint) (uchar) row->data[4][0];
1471  field->decimals=(uint) (uchar) row->data[4][1];
1472  }
1473  if (IS_NUM(field->type))
1474  field->flags|= NUM_FLAG;
1475  if (default_value && row->data[5])
1476  {
1477  field->def=strdup_root(alloc,(char*) row->data[5]);
1478  field->def_length= lengths[5];
1479  }
1480  else
1481  field->def=0;
1482  field->max_length= 0;
1483  }
1484  }
1485 #endif /* DELETE_SUPPORT_OF_4_0_PROTOCOL */
1486  free_rows(data); /* Free old data */
1487  DBUG_RETURN(result);
1488 }
1489 
1490 /* Read all rows (fields or data) from server */
1491 
1492 MYSQL_DATA *cli_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
1493  unsigned int fields)
1494 {
1495  uint field;
1496  ulong pkt_len;
1497  ulong len;
1498  uchar *cp;
1499  char *to, *end_to;
1500  MYSQL_DATA *result;
1501  MYSQL_ROWS **prev_ptr,*cur;
1502  NET *net = &mysql->net;
1503  DBUG_ENTER("cli_read_rows");
1504 
1505  if ((pkt_len= cli_safe_read(mysql)) == packet_error)
1506  DBUG_RETURN(0);
1507  if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA),
1508  MYF(MY_WME | MY_ZEROFILL))))
1509  {
1510  set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
1511  DBUG_RETURN(0);
1512  }
1513  init_alloc_root(&result->alloc,8192,0); /* Assume rowlength < 8192 */
1514  result->alloc.min_malloc=sizeof(MYSQL_ROWS);
1515  prev_ptr= &result->data;
1516  result->rows=0;
1517  result->fields=fields;
1518 
1519  /*
1520  The last EOF packet is either a single 254 character or (in MySQL 4.1)
1521  254 followed by 1-7 status bytes.
1522 
1523  This doesn't conflict with normal usage of 254 which stands for a
1524  string where the length of the string is 8 bytes. (see net_field_length())
1525  */
1526 
1527  while (*(cp=net->read_pos) != 254 || pkt_len >= 8)
1528  {
1529  result->rows++;
1530  if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc,
1531  sizeof(MYSQL_ROWS))) ||
1532  !(cur->data= ((MYSQL_ROW)
1533  alloc_root(&result->alloc,
1534  (fields+1)*sizeof(char *)+pkt_len))))
1535  {
1536  free_rows(result);
1537  set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
1538  DBUG_RETURN(0);
1539  }
1540  *prev_ptr=cur;
1541  prev_ptr= &cur->next;
1542  to= (char*) (cur->data+fields+1);
1543  end_to=to+pkt_len-1;
1544  for (field=0 ; field < fields ; field++)
1545  {
1546  if ((len=(ulong) net_field_length(&cp)) == NULL_LENGTH)
1547  { /* null field */
1548  cur->data[field] = 0;
1549  }
1550  else
1551  {
1552  cur->data[field] = to;
1553  if (len > (ulong) (end_to - to))
1554  {
1555  free_rows(result);
1556  set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
1557  DBUG_RETURN(0);
1558  }
1559  memcpy(to,(char*) cp,len); to[len]=0;
1560  to+=len+1;
1561  cp+=len;
1562  if (mysql_fields)
1563  {
1564  if (mysql_fields[field].max_length < len)
1565  mysql_fields[field].max_length=len;
1566  }
1567  }
1568  }
1569  cur->data[field]=to; /* End of last field */
1570  if ((pkt_len=cli_safe_read(mysql)) == packet_error)
1571  {
1572  free_rows(result);
1573  DBUG_RETURN(0);
1574  }
1575  }
1576  *prev_ptr=0; /* last pointer is null */
1577  if (pkt_len > 1) /* MySQL 4.1 protocol */
1578  {
1579  mysql->warning_count= uint2korr(cp+1);
1580  mysql->server_status= uint2korr(cp+3);
1581  DBUG_PRINT("info",("status: %u warning_count: %u",
1582  mysql->server_status, mysql->warning_count));
1583  }
1584  DBUG_PRINT("exit", ("Got %lu rows", (ulong) result->rows));
1585  DBUG_RETURN(result);
1586 }
1587 
1588 /*
1589  Read one row. Uses packet buffer as storage for fields.
1590  When next packet is read, the previous field values are destroyed
1591 */
1592 
1593 
1594 static int
1595 read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
1596 {
1597  uint field;
1598  ulong pkt_len,len;
1599  uchar *pos, *prev_pos, *end_pos;
1600  NET *net= &mysql->net;
1601 
1602  if ((pkt_len=cli_safe_read(mysql)) == packet_error)
1603  return -1;
1604  if (pkt_len <= 8 && net->read_pos[0] == 254)
1605  {
1606  if (pkt_len > 1) /* MySQL 4.1 protocol */
1607  {
1608  mysql->warning_count= uint2korr(net->read_pos+1);
1609  mysql->server_status= uint2korr(net->read_pos+3);
1610  }
1611  return 1; /* End of data */
1612  }
1613  prev_pos= 0; /* allowed to write at packet[-1] */
1614  pos=net->read_pos;
1615  end_pos=pos+pkt_len;
1616  for (field=0 ; field < fields ; field++)
1617  {
1618  if ((len=(ulong) net_field_length(&pos)) == NULL_LENGTH)
1619  { /* null field */
1620  row[field] = 0;
1621  *lengths++=0;
1622  }
1623  else
1624  {
1625  if (len > (ulong) (end_pos - pos))
1626  {
1627  set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
1628  return -1;
1629  }
1630  row[field] = (char*) pos;
1631  pos+=len;
1632  *lengths++=len;
1633  }
1634  if (prev_pos)
1635  *prev_pos=0; /* Terminate prev field */
1636  prev_pos=pos;
1637  }
1638  row[field]=(char*) prev_pos+1; /* End of last field */
1639  *prev_pos=0; /* Terminate last field */
1640  return 0;
1641 }
1642 
1643 
1644 /****************************************************************************
1645  Init MySQL structure or allocate one
1646 ****************************************************************************/
1647 
1648 MYSQL * STDCALL
1649 mysql_init(MYSQL *mysql)
1650 {
1651  if (mysql_server_init(0, NULL, NULL))
1652  return 0;
1653  if (!mysql)
1654  {
1655  if (!(mysql=(MYSQL*) my_malloc(sizeof(*mysql),MYF(MY_WME | MY_ZEROFILL))))
1656  {
1657  set_mysql_error(NULL, CR_OUT_OF_MEMORY, unknown_sqlstate);
1658  return 0;
1659  }
1660  mysql->free_me=1;
1661  }
1662  else
1663  memset(mysql, 0, sizeof(*(mysql)));
1664  mysql->charset=default_client_charset_info;
1665  strmov(mysql->net.sqlstate, not_error_sqlstate);
1666 
1667  /*
1668  Only enable LOAD DATA INFILE by default if configured with
1669  --enable-local-infile
1670  */
1671 
1672 #if defined(ENABLED_LOCAL_INFILE) && !defined(MYSQL_SERVER)
1673  mysql->options.client_flag|= CLIENT_LOCAL_FILES;
1674 #endif
1675 
1676 #ifdef HAVE_SMEM
1677  mysql->options.shared_memory_base_name= (char*) def_shared_memory_base_name;
1678 #endif
1679 
1680  mysql->options.methods_to_use= MYSQL_OPT_GUESS_CONNECTION;
1681  mysql->options.report_data_truncation= TRUE; /* default */
1682 
1683  /*
1684  By default we don't reconnect because it could silently corrupt data (after
1685  reconnection you potentially lose table locks, user variables, session
1686  variables (transactions but they are specifically dealt with in
1687  mysql_reconnect()).
1688  This is a change: < 5.0.3 mysql->reconnect was set to 1 by default.
1689  How this change impacts existing apps:
1690  - existing apps which relyed on the default will see a behaviour change;
1691  they will have to set reconnect=1 after mysql_real_connect().
1692  - existing apps which explicitely asked for reconnection (the only way they
1693  could do it was by setting mysql.reconnect to 1 after mysql_real_connect())
1694  will not see a behaviour change.
1695  - existing apps which explicitely asked for no reconnection
1696  (mysql.reconnect=0) will not see a behaviour change.
1697  */
1698  mysql->reconnect= 0;
1699 
1700  mysql->options.secure_auth= TRUE;
1701 
1702  return mysql;
1703 }
1704 
1705 
1706 /*
1707  Fill in SSL part of MYSQL structure and set 'use_ssl' flag.
1708  NB! Errors are not reported until you do mysql_real_connect.
1709 */
1710 
1711 #define strdup_if_not_null(A) (A) == 0 ? 0 : my_strdup((A),MYF(MY_WME))
1712 
1713 my_bool STDCALL
1714 mysql_ssl_set(MYSQL *mysql __attribute__((unused)) ,
1715  const char *key __attribute__((unused)),
1716  const char *cert __attribute__((unused)),
1717  const char *ca __attribute__((unused)),
1718  const char *capath __attribute__((unused)),
1719  const char *cipher __attribute__((unused)))
1720 {
1721  my_bool result= 0;
1722  DBUG_ENTER("mysql_ssl_set");
1723 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
1724  result=
1725  mysql_options(mysql, MYSQL_OPT_SSL_KEY, key) +
1726  mysql_options(mysql, MYSQL_OPT_SSL_CERT, cert) +
1727  mysql_options(mysql, MYSQL_OPT_SSL_CA, ca) +
1728  mysql_options(mysql, MYSQL_OPT_SSL_CAPATH, capath) +
1729  mysql_options(mysql, MYSQL_OPT_SSL_CIPHER, cipher)
1730  ? 1 : 0;
1731 #endif
1732  DBUG_RETURN(result);
1733 }
1734 
1735 
1736 /*
1737  Free strings in the SSL structure and clear 'use_ssl' flag.
1738  NB! Errors are not reported until you do mysql_real_connect.
1739 */
1740 
1741 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
1742 
1743 static void
1744 mysql_ssl_free(MYSQL *mysql __attribute__((unused)))
1745 {
1746  struct st_VioSSLFd *ssl_fd= (struct st_VioSSLFd*) mysql->connector_fd;
1747  DBUG_ENTER("mysql_ssl_free");
1748 
1749  my_free(mysql->options.ssl_key);
1750  my_free(mysql->options.ssl_cert);
1751  my_free(mysql->options.ssl_ca);
1752  my_free(mysql->options.ssl_capath);
1753  my_free(mysql->options.ssl_cipher);
1754  if (mysql->options.extension)
1755  {
1756  my_free(mysql->options.extension->ssl_crl);
1757  my_free(mysql->options.extension->ssl_crlpath);
1758  }
1759  if (ssl_fd)
1760  SSL_CTX_free(ssl_fd->ssl_context);
1761  my_free(mysql->connector_fd);
1762  mysql->options.ssl_key = 0;
1763  mysql->options.ssl_cert = 0;
1764  mysql->options.ssl_ca = 0;
1765  mysql->options.ssl_capath = 0;
1766  mysql->options.ssl_cipher= 0;
1767  if (mysql->options.extension)
1768  {
1769  mysql->options.extension->ssl_crl = 0;
1770  mysql->options.extension->ssl_crlpath = 0;
1771  }
1772  mysql->options.use_ssl = FALSE;
1773  mysql->connector_fd = 0;
1774  DBUG_VOID_RETURN;
1775 }
1776 
1777 #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
1778 
1779 /*
1780  Return the SSL cipher (if any) used for current
1781  connection to the server.
1782 
1783  SYNOPSYS
1784  mysql_get_ssl_cipher()
1785  mysql pointer to the mysql connection
1786 
1787 */
1788 
1789 const char * STDCALL
1790 mysql_get_ssl_cipher(MYSQL *mysql __attribute__((unused)))
1791 {
1792  DBUG_ENTER("mysql_get_ssl_cipher");
1793 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
1794  if (mysql->net.vio && mysql->net.vio->ssl_arg)
1795  DBUG_RETURN(SSL_get_cipher_name((SSL*)mysql->net.vio->ssl_arg));
1796 #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
1797  DBUG_RETURN(NULL);
1798 }
1799 
1800 
1801 /*
1802  Check the server's (subject) Common Name against the
1803  hostname we connected to
1804 
1805  SYNOPSIS
1806  ssl_verify_server_cert()
1807  vio pointer to a SSL connected vio
1808  server_hostname name of the server that we connected to
1809  errptr if we fail, we'll return (a pointer to a string
1810  describing) the reason here
1811 
1812  RETURN VALUES
1813  0 Success
1814  1 Failed to validate server
1815 
1816  */
1817 
1818 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
1819 
1820 static int ssl_verify_server_cert(Vio *vio, const char* server_hostname, const char **errptr)
1821 {
1822  SSL *ssl;
1823  X509 *server_cert;
1824  char *cp1, *cp2;
1825  char buf[256];
1826  DBUG_ENTER("ssl_verify_server_cert");
1827  DBUG_PRINT("enter", ("server_hostname: %s", server_hostname));
1828 
1829  if (!(ssl= (SSL*)vio->ssl_arg))
1830  {
1831  *errptr= "No SSL pointer found";
1832  DBUG_RETURN(1);
1833  }
1834 
1835  if (!server_hostname)
1836  {
1837  *errptr= "No server hostname supplied";
1838  DBUG_RETURN(1);
1839  }
1840 
1841  if (!(server_cert= SSL_get_peer_certificate(ssl)))
1842  {
1843  *errptr= "Could not get server certificate";
1844  DBUG_RETURN(1);
1845  }
1846 
1847  /*
1848  We already know that the certificate exchanged was valid; the SSL library
1849  handled that. Now we need to verify that the contents of the certificate
1850  are what we expect.
1851  */
1852 
1853  X509_NAME_oneline(X509_get_subject_name(server_cert), buf, sizeof(buf));
1854  X509_free (server_cert);
1855 
1856  DBUG_PRINT("info", ("hostname in cert: %s", buf));
1857  cp1= strstr(buf, "/CN=");
1858  if (cp1)
1859  {
1860  cp1+= 4; /* Skip the "/CN=" that we found */
1861  /* Search for next / which might be the delimiter for email */
1862  cp2= strchr(cp1, '/');
1863  if (cp2)
1864  *cp2= '\0';
1865  DBUG_PRINT("info", ("Server hostname in cert: %s", cp1));
1866  if (!strcmp(cp1, server_hostname))
1867  {
1868  /* Success */
1869  DBUG_RETURN(0);
1870  }
1871  }
1872  *errptr= "SSL certificate validation failure";
1873  DBUG_RETURN(1);
1874 }
1875 
1876 #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
1877 
1878 
1879 /*
1880  Note that the mysql argument must be initialized with mysql_init()
1881  before calling mysql_real_connect !
1882 */
1883 
1884 static my_bool cli_read_query_result(MYSQL *mysql);
1885 static MYSQL_RES *cli_use_result(MYSQL *mysql);
1886 
1887 int cli_read_change_user_result(MYSQL *mysql)
1888 {
1889  return cli_safe_read(mysql);
1890 }
1891 
1892 static MYSQL_METHODS client_methods=
1893 {
1894  cli_read_query_result, /* read_query_result */
1895  cli_advanced_command, /* advanced_command */
1896  cli_read_rows, /* read_rows */
1897  cli_use_result, /* use_result */
1898  cli_fetch_lengths, /* fetch_lengths */
1899  cli_flush_use_result, /* flush_use_result */
1900  cli_read_change_user_result /* read_change_user_result */
1901 #ifndef MYSQL_SERVER
1902  ,cli_list_fields, /* list_fields */
1903  cli_read_prepare_result, /* read_prepare_result */
1904  cli_stmt_execute, /* stmt_execute */
1905  cli_read_binary_rows, /* read_binary_rows */
1906  cli_unbuffered_fetch, /* unbuffered_fetch */
1907  NULL, /* free_embedded_thd */
1908  cli_read_statistics, /* read_statistics */
1909  cli_read_query_result, /* next_result */
1910  cli_read_binary_rows /* read_rows_from_cursor */
1911 #endif
1912 };
1913 
1914 
1915 
1916 typedef enum my_cs_match_type_enum
1917 {
1918  /* MySQL and OS charsets are fully compatible */
1919  my_cs_exact,
1920  /* MySQL charset is very close to OS charset */
1921  my_cs_approx,
1922  /*
1923  MySQL knows this charset, but it is not supported as client character set.
1924  */
1925  my_cs_unsupp
1926 } my_cs_match_type;
1927 
1928 
1929 typedef struct str2str_st
1930 {
1931  const char *os_name;
1932  const char *my_name;
1933  my_cs_match_type param;
1934 } MY_CSET_OS_NAME;
1935 
1936 const MY_CSET_OS_NAME charsets[]=
1937 {
1938 #ifdef __WIN__
1939  {"cp437", "cp850", my_cs_approx},
1940  {"cp850", "cp850", my_cs_exact},
1941  {"cp852", "cp852", my_cs_exact},
1942  {"cp858", "cp850", my_cs_approx},
1943  {"cp866", "cp866", my_cs_exact},
1944  {"cp874", "tis620", my_cs_approx},
1945  {"cp932", "cp932", my_cs_exact},
1946  {"cp936", "gbk", my_cs_approx},
1947  {"cp949", "euckr", my_cs_approx},
1948  {"cp950", "big5", my_cs_exact},
1949  {"cp1200", "utf16le", my_cs_unsupp},
1950  {"cp1201", "utf16", my_cs_unsupp},
1951  {"cp1250", "cp1250", my_cs_exact},
1952  {"cp1251", "cp1251", my_cs_exact},
1953  {"cp1252", "latin1", my_cs_exact},
1954  {"cp1253", "greek", my_cs_exact},
1955  {"cp1254", "latin5", my_cs_exact},
1956  {"cp1255", "hebrew", my_cs_approx},
1957  {"cp1256", "cp1256", my_cs_exact},
1958  {"cp1257", "cp1257", my_cs_exact},
1959  {"cp10000", "macroman", my_cs_exact},
1960  {"cp10001", "sjis", my_cs_approx},
1961  {"cp10002", "big5", my_cs_approx},
1962  {"cp10008", "gb2312", my_cs_approx},
1963  {"cp10021", "tis620", my_cs_approx},
1964  {"cp10029", "macce", my_cs_exact},
1965  {"cp12001", "utf32", my_cs_unsupp},
1966  {"cp20107", "swe7", my_cs_exact},
1967  {"cp20127", "latin1", my_cs_approx},
1968  {"cp20866", "koi8r", my_cs_exact},
1969  {"cp20932", "ujis", my_cs_exact},
1970  {"cp20936", "gb2312", my_cs_approx},
1971  {"cp20949", "euckr", my_cs_approx},
1972  {"cp21866", "koi8u", my_cs_exact},
1973  {"cp28591", "latin1", my_cs_approx},
1974  {"cp28592", "latin2", my_cs_exact},
1975  {"cp28597", "greek", my_cs_exact},
1976  {"cp28598", "hebrew", my_cs_exact},
1977  {"cp28599", "latin5", my_cs_exact},
1978  {"cp28603", "latin7", my_cs_exact},
1979 #ifdef UNCOMMENT_THIS_WHEN_WL_4579_IS_DONE
1980  {"cp28605", "latin9", my_cs_exact},
1981 #endif
1982  {"cp38598", "hebrew", my_cs_exact},
1983  {"cp51932", "ujis", my_cs_exact},
1984  {"cp51936", "gb2312", my_cs_exact},
1985  {"cp51949", "euckr", my_cs_exact},
1986  {"cp51950", "big5", my_cs_exact},
1987 #ifdef UNCOMMENT_THIS_WHEN_WL_WL_4024_IS_DONE
1988  {"cp54936", "gb18030", my_cs_exact},
1989 #endif
1990  {"cp65001", "utf8", my_cs_exact},
1991 
1992 #else /* not Windows */
1993 
1994  {"646", "latin1", my_cs_approx}, /* Default on Solaris */
1995  {"ANSI_X3.4-1968", "latin1", my_cs_approx},
1996  {"ansi1251", "cp1251", my_cs_exact},
1997  {"armscii8", "armscii8", my_cs_exact},
1998  {"armscii-8", "armscii8", my_cs_exact},
1999  {"ASCII", "latin1", my_cs_approx},
2000  {"Big5", "big5", my_cs_exact},
2001  {"cp1251", "cp1251", my_cs_exact},
2002  {"cp1255", "hebrew", my_cs_approx},
2003  {"CP866", "cp866", my_cs_exact},
2004  {"eucCN", "gb2312", my_cs_exact},
2005  {"euc-CN", "gb2312", my_cs_exact},
2006  {"eucJP", "ujis", my_cs_exact},
2007  {"euc-JP", "ujis", my_cs_exact},
2008  {"eucKR", "euckr", my_cs_exact},
2009  {"euc-KR", "euckr", my_cs_exact},
2010 #ifdef UNCOMMENT_THIS_WHEN_WL_WL_4024_IS_DONE
2011  {"gb18030", "gb18030", my_cs_exact},
2012 #endif
2013  {"gb2312", "gb2312", my_cs_exact},
2014  {"gbk", "gbk", my_cs_exact},
2015  {"georgianps", "geostd8", my_cs_exact},
2016  {"georgian-ps", "geostd8", my_cs_exact},
2017  {"IBM-1252", "cp1252", my_cs_exact},
2018 
2019  {"iso88591", "latin1", my_cs_approx},
2020  {"ISO_8859-1", "latin1", my_cs_approx},
2021  {"ISO8859-1", "latin1", my_cs_approx},
2022  {"ISO-8859-1", "latin1", my_cs_approx},
2023 
2024  {"iso885913", "latin7", my_cs_exact},
2025  {"ISO_8859-13", "latin7", my_cs_exact},
2026  {"ISO8859-13", "latin7", my_cs_exact},
2027  {"ISO-8859-13", "latin7", my_cs_exact},
2028 
2029 #ifdef UNCOMMENT_THIS_WHEN_WL_4579_IS_DONE
2030  {"iso885915", "latin9", my_cs_exact},
2031  {"ISO_8859-15", "latin9", my_cs_exact},
2032  {"ISO8859-15", "latin9", my_cs_exact},
2033  {"ISO-8859-15", "latin9", my_cs_exact},
2034 #endif
2035 
2036  {"iso88592", "latin2", my_cs_exact},
2037  {"ISO_8859-2", "latin2", my_cs_exact},
2038  {"ISO8859-2", "latin2", my_cs_exact},
2039  {"ISO-8859-2", "latin2", my_cs_exact},
2040 
2041  {"iso88597", "greek", my_cs_exact},
2042  {"ISO_8859-7", "greek", my_cs_exact},
2043  {"ISO8859-7", "greek", my_cs_exact},
2044  {"ISO-8859-7", "greek", my_cs_exact},
2045 
2046  {"iso88598", "hebrew", my_cs_exact},
2047  {"ISO_8859-8", "hebrew", my_cs_exact},
2048  {"ISO8859-8", "hebrew", my_cs_exact},
2049  {"ISO-8859-8", "hebrew", my_cs_exact},
2050 
2051  {"iso88599", "latin5", my_cs_exact},
2052  {"ISO_8859-9", "latin5", my_cs_exact},
2053  {"ISO8859-9", "latin5", my_cs_exact},
2054  {"ISO-8859-9", "latin5", my_cs_exact},
2055 
2056  {"koi8r", "koi8r", my_cs_exact},
2057  {"KOI8-R", "koi8r", my_cs_exact},
2058  {"koi8u", "koi8u", my_cs_exact},
2059  {"KOI8-U", "koi8u", my_cs_exact},
2060 
2061  {"roman8", "hp8", my_cs_exact}, /* Default on HP UX */
2062 
2063  {"Shift_JIS", "sjis", my_cs_exact},
2064  {"SJIS", "sjis", my_cs_exact},
2065  {"shiftjisx0213", "sjis", my_cs_exact},
2066 
2067  {"tis620", "tis620", my_cs_exact},
2068  {"tis-620", "tis620", my_cs_exact},
2069 
2070  {"ujis", "ujis", my_cs_exact},
2071 
2072  {"US-ASCII", "latin1", my_cs_approx},
2073 
2074  {"utf8", "utf8", my_cs_exact},
2075  {"utf-8", "utf8", my_cs_exact},
2076 #endif
2077  {NULL, NULL, 0}
2078 };
2079 
2080 
2081 static const char *
2082 my_os_charset_to_mysql_charset(const char *csname)
2083 {
2084  const MY_CSET_OS_NAME *csp;
2085  for (csp= charsets; csp->os_name; csp++)
2086  {
2087  if (!my_strcasecmp(&my_charset_latin1, csp->os_name, csname))
2088  {
2089  switch (csp->param)
2090  {
2091  case my_cs_exact:
2092  return csp->my_name;
2093 
2094  case my_cs_approx:
2095  /*
2096  Maybe we should print a warning eventually:
2097  character set correspondence is not exact.
2098  */
2099  return csp->my_name;
2100 
2101  default:
2102  my_printf_error(ER_UNKNOWN_ERROR,
2103  "OS character set '%s'"
2104  " is not supported by MySQL client",
2105  MYF(0), csp->my_name);
2106  goto def;
2107  }
2108  }
2109  }
2110 
2111  my_printf_error(ER_UNKNOWN_ERROR,
2112  "Unknown OS character set '%s'.",
2113  MYF(0), csname);
2114 
2115 def:
2116  csname= MYSQL_DEFAULT_CHARSET_NAME;
2117  my_printf_error(ER_UNKNOWN_ERROR,
2118  "Switching to the default character set '%s'.",
2119  MYF(0), csname);
2120  return csname;
2121 }
2122 
2123 
2124 #ifndef __WIN__
2125 #include <stdlib.h> /* for getenv() */
2126 #ifdef HAVE_LANGINFO_H
2127 #include <langinfo.h>
2128 #endif
2129 #ifdef HAVE_LOCALE_H
2130 #include <locale.h>
2131 #endif
2132 #endif /* __WIN__ */
2133 
2134 
2135 static int
2136 mysql_autodetect_character_set(MYSQL *mysql)
2137 {
2138  const char *csname= MYSQL_DEFAULT_CHARSET_NAME;
2139 
2140 #ifdef __WIN__
2141  char cpbuf[64];
2142  {
2143  my_snprintf(cpbuf, sizeof(cpbuf), "cp%d", (int) GetConsoleCP());
2144  csname= my_os_charset_to_mysql_charset(cpbuf);
2145  }
2146 #elif defined(HAVE_SETLOCALE) && defined(HAVE_NL_LANGINFO)
2147  {
2148  if (setlocale(LC_CTYPE, "") && (csname= nl_langinfo(CODESET)))
2149  csname= my_os_charset_to_mysql_charset(csname);
2150  }
2151 #endif
2152 
2153  if (mysql->options.charset_name)
2154  my_free(mysql->options.charset_name);
2155  if (!(mysql->options.charset_name= my_strdup(csname, MYF(MY_WME))))
2156  return 1;
2157  return 0;
2158 }
2159 
2160 
2161 static void
2162 mysql_set_character_set_with_default_collation(MYSQL *mysql)
2163 {
2164  const char *save= charsets_dir;
2165  if (mysql->options.charset_dir)
2166  charsets_dir=mysql->options.charset_dir;
2167 
2168  if ((mysql->charset= get_charset_by_csname(mysql->options.charset_name,
2169  MY_CS_PRIMARY, MYF(MY_WME))))
2170  {
2171  /* Try to set compiled default collation when it's possible. */
2172  CHARSET_INFO *collation;
2173  if ((collation=
2174  get_charset_by_name(MYSQL_DEFAULT_COLLATION_NAME, MYF(MY_WME))) &&
2175  my_charset_same(mysql->charset, collation))
2176  {
2177  mysql->charset= collation;
2178  }
2179  else
2180  {
2181  /*
2182  Default compiled collation not found, or is not applicable
2183  to the requested character set.
2184  Continue with the default collation of the character set.
2185  */
2186  }
2187  }
2188  charsets_dir= save;
2189 }
2190 
2191 
2192 C_MODE_START
2193 int mysql_init_character_set(MYSQL *mysql)
2194 {
2195  /* Set character set */
2196  if (!mysql->options.charset_name)
2197  {
2198  if (!(mysql->options.charset_name=
2199  my_strdup(MYSQL_DEFAULT_CHARSET_NAME,MYF(MY_WME))))
2200  return 1;
2201  }
2202  else if (!strcmp(mysql->options.charset_name,
2203  MYSQL_AUTODETECT_CHARSET_NAME) &&
2204  mysql_autodetect_character_set(mysql))
2205  return 1;
2206 
2207  mysql_set_character_set_with_default_collation(mysql);
2208 
2209  if (!mysql->charset)
2210  {
2211  if (mysql->options.charset_dir)
2212  set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate,
2213  ER(CR_CANT_READ_CHARSET),
2214  mysql->options.charset_name,
2215  mysql->options.charset_dir);
2216  else
2217  {
2218  char cs_dir_name[FN_REFLEN];
2219  get_charsets_dir(cs_dir_name);
2220  set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate,
2221  ER(CR_CANT_READ_CHARSET),
2222  mysql->options.charset_name,
2223  cs_dir_name);
2224  }
2225  return 1;
2226  }
2227  return 0;
2228 }
2229 C_MODE_END
2230 
2231 /*********** client side authentication support **************************/
2232 
2233 typedef struct st_mysql_client_plugin_AUTHENTICATION auth_plugin_t;
2234 static int client_mpvio_write_packet(struct st_plugin_vio*, const uchar*, int);
2235 static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
2236 static int old_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
2237 static int clear_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
2238 
2239 static auth_plugin_t native_password_client_plugin=
2240 {
2241  MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
2242  MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
2243  native_password_plugin_name,
2244  "R.J.Silk, Sergei Golubchik",
2245  "Native MySQL authentication",
2246  {1, 0, 0},
2247  "GPL",
2248  NULL,
2249  NULL,
2250  NULL,
2251  NULL,
2252  native_password_auth_client
2253 };
2254 
2255 static auth_plugin_t old_password_client_plugin=
2256 {
2257  MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
2258  MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
2259  old_password_plugin_name,
2260  "R.J.Silk, Sergei Golubchik",
2261  "Old MySQL-3.23 authentication",
2262  {1, 0, 0},
2263  "GPL",
2264  NULL,
2265  NULL,
2266  NULL,
2267  NULL,
2268  old_password_auth_client
2269 };
2270 
2271 static auth_plugin_t clear_password_client_plugin=
2272 {
2273  MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
2274  MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
2275  "mysql_clear_password",
2276  "Georgi Kodinov",
2277  "Clear password authentication plugin",
2278  {0,1,0},
2279  "GPL",
2280  NULL,
2281  NULL,
2282  NULL,
2283  NULL,
2284  clear_password_auth_client
2285 };
2286 
2287 #if defined(HAVE_OPENSSL)
2288 static auth_plugin_t sha256_password_client_plugin=
2289 {
2290  MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
2291  MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
2292  "sha256_password",
2293  "Oracle Inc",
2294  "SHA256 based authentication with salt",
2295  {1, 0, 0},
2296  "GPL",
2297  NULL,
2298  sha256_password_init,
2299  sha256_password_deinit,
2300  NULL,
2301  sha256_password_auth_client
2302 };
2303 #endif
2304 #ifdef AUTHENTICATION_WIN
2305 extern auth_plugin_t win_auth_client_plugin;
2306 #endif
2307 
2308 struct st_mysql_client_plugin *mysql_client_builtins[]=
2309 {
2310  (struct st_mysql_client_plugin *)&native_password_client_plugin,
2311  (struct st_mysql_client_plugin *)&old_password_client_plugin,
2312  (struct st_mysql_client_plugin *)&clear_password_client_plugin,
2313 #if defined(HAVE_OPENSSL)
2314  (struct st_mysql_client_plugin *) &sha256_password_client_plugin,
2315 #endif
2316 #ifdef AUTHENTICATION_WIN
2317  (struct st_mysql_client_plugin *)&win_auth_client_plugin,
2318 #endif
2319  0
2320 };
2321 
2322 
2323 static uchar *
2324 write_length_encoded_string3(uchar *buf, char *string, size_t length)
2325 {
2326  buf= net_store_length(buf, length);
2327  memcpy(buf, string, length);
2328  buf+= length;
2329  return buf;
2330 }
2331 
2332 
2333 uchar *
2334 send_client_connect_attrs(MYSQL *mysql, uchar *buf)
2335 {
2336  /* check if the server supports connection attributes */
2337  if (mysql->server_capabilities & CLIENT_CONNECT_ATTRS)
2338  {
2339 
2340  /* Always store the length if the client supports it */
2341  buf= net_store_length(buf,
2342  mysql->options.extension ?
2343  mysql->options.extension->connection_attributes_length :
2344  0);
2345 
2346  /* check if we have connection attributes */
2347  if (mysql->options.extension &&
2348  my_hash_inited(&mysql->options.extension->connection_attributes))
2349  {
2350  HASH *attrs= &mysql->options.extension->connection_attributes;
2351  ulong idx;
2352 
2353  /* loop over and dump the connection attributes */
2354  for (idx= 0; idx < attrs->records; idx++)
2355  {
2356  LEX_STRING *attr= (LEX_STRING *) my_hash_element(attrs, idx);
2357  LEX_STRING *key= attr, *value= attr + 1;
2358 
2359  /* we can't have zero length keys */
2360  DBUG_ASSERT(key->length);
2361 
2362  buf= write_length_encoded_string3(buf, key->str, key->length);
2363  buf= write_length_encoded_string3(buf, value->str, value->length);
2364  }
2365  }
2366  }
2367  return buf;
2368 }
2369 
2370 
2371 static size_t get_length_store_length(size_t length)
2372 {
2373  /* as defined in net_store_length */
2374  #define MAX_VARIABLE_STRING_LENGTH 9
2375  uchar length_buffer[MAX_VARIABLE_STRING_LENGTH], *ptr;
2376 
2377  ptr= net_store_length(length_buffer, length);
2378 
2379  return ptr - &length_buffer[0];
2380 }
2381 
2382 
2383 /* this is a "superset" of MYSQL_PLUGIN_VIO, in C++ I use inheritance */
2384 typedef struct {
2385  int (*read_packet)(struct st_plugin_vio *vio, uchar **buf);
2386  int (*write_packet)(struct st_plugin_vio *vio, const uchar *pkt, int pkt_len);
2387  void (*info)(struct st_plugin_vio *vio, struct st_plugin_vio_info *info);
2388  /* -= end of MYSQL_PLUGIN_VIO =- */
2389  MYSQL *mysql;
2390  auth_plugin_t *plugin;
2391  const char *db;
2392  struct {
2393  uchar *pkt;
2394  uint pkt_len;
2395  } cached_server_reply;
2396  int packets_read, packets_written;
2399 } MCPVIO_EXT;
2400 
2401 
2402 /*
2403  Write 1-8 bytes of string length header infromation to dest depending on
2404  value of src_len, then copy src_len bytes from src to dest.
2405 
2406  @param dest Destination buffer of size src_len+8
2407  @param dest_end One byte past the end of the dest buffer
2408  @param src Source buff of size src_len
2409  @param src_end One byte past the end of the src buffer
2410 
2411  @return pointer dest+src_len+header size or NULL if
2412 */
2413 
2414 char *write_length_encoded_string4(char *dest, char *dest_end, char *src,
2415  char *src_end)
2416 {
2417  size_t src_len= (size_t)(src_end - src);
2418  uchar *to= net_store_length((uchar*) dest, src_len);
2419  if ((char*)(to + src_len) >= dest_end)
2420  return NULL;
2421  memcpy(to, src, src_len);
2422  return (char*)(to + src_len);
2423 }
2424 
2425 
2426 /*
2427  Write 1 byte of string length header information to dest and
2428  copy src_len bytes from src to dest.
2429 */
2430 char *write_string(char *dest, char *dest_end, char *src, char *src_end)
2431 {
2432  size_t src_len= (size_t)(src_end - src);
2433  uchar *to= NULL;
2434  if (src_len >= 251)
2435  return NULL;
2436  *dest=(uchar) src_len;
2437  to= (uchar*) dest+1;
2438  if ((char*)(to + src_len) >= dest_end)
2439  return NULL;
2440  memcpy(to, src, src_len);
2441  return (char*)(to + src_len);
2442 }
2462 static int send_change_user_packet(MCPVIO_EXT *mpvio,
2463  const uchar *data, int data_len)
2464 {
2465  MYSQL *mysql= mpvio->mysql;
2466  char *buff, *end;
2467  int res= 1;
2468  size_t connect_attrs_len=
2469  (mysql->server_capabilities & CLIENT_CONNECT_ATTRS &&
2470  mysql->options.extension) ?
2471  mysql->options.extension->connection_attributes_length : 0;
2472 
2473  buff= my_alloca(USERNAME_LENGTH + data_len + 1 + NAME_LEN + 2 + NAME_LEN +
2474  connect_attrs_len + 9 /* for the length of the attrs */);
2475 
2476  end= strmake(buff, mysql->user, USERNAME_LENGTH) + 1;
2477 
2478  if (!data_len)
2479  *end++= 0;
2480  else
2481  {
2482  if (mysql->client_flag & CLIENT_SECURE_CONNECTION)
2483  {
2484  DBUG_ASSERT(data_len <= 255);
2485  if (data_len > 255)
2486  {
2487  set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
2488  goto error;
2489  }
2490  *end++= data_len;
2491  }
2492  else
2493  {
2494  DBUG_ASSERT(data_len == SCRAMBLE_LENGTH_323 + 1);
2495  DBUG_ASSERT(data[SCRAMBLE_LENGTH_323] == 0);
2496  }
2497  memcpy(end, data, data_len);
2498  end+= data_len;
2499  }
2500  end= strmake(end, mpvio->db ? mpvio->db : "", NAME_LEN) + 1;
2501 
2502  if (mysql->server_capabilities & CLIENT_PROTOCOL_41)
2503  {
2504  int2store(end, (ushort) mysql->charset->number);
2505  end+= 2;
2506  }
2507 
2508  if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
2509  end= strmake(end, mpvio->plugin->name, NAME_LEN) + 1;
2510 
2511  end= (char *) send_client_connect_attrs(mysql, (uchar *) end);
2512 
2513  res= simple_command(mysql, COM_CHANGE_USER,
2514  (uchar*)buff, (ulong)(end-buff), 1);
2515 
2516 error:
2517  my_afree(buff);
2518  return res;
2519 }
2520 
2521 
2522 #define MAX_CONNECTION_ATTR_STORAGE_LENGTH 65536
2523 
2554 static int send_client_reply_packet(MCPVIO_EXT *mpvio,
2555  const uchar *data, int data_len)
2556 {
2557  MYSQL *mysql= mpvio->mysql;
2558  NET *net= &mysql->net;
2559  char *buff, *end;
2560  size_t buff_size;
2561  size_t connect_attrs_len=
2562  (mysql->server_capabilities & CLIENT_CONNECT_ATTRS &&
2563  mysql->options.extension) ?
2564  mysql->options.extension->connection_attributes_length : 0;
2565 
2566  DBUG_ASSERT(connect_attrs_len < MAX_CONNECTION_ATTR_STORAGE_LENGTH);
2567 
2568 
2569  /*
2570  see end= buff+32 below, fixed size of the packet is 32 bytes.
2571  +9 because data is a length encoded binary where meta data size is max 9.
2572  */
2573  buff_size= 33 + USERNAME_LENGTH + data_len + 9 + NAME_LEN + NAME_LEN + connect_attrs_len + 9;
2574  buff= my_alloca(buff_size);
2575 
2576  mysql->client_flag|= mysql->options.client_flag;
2577  mysql->client_flag|= CLIENT_CAPABILITIES;
2578 
2579  if (mysql->client_flag & CLIENT_MULTI_STATEMENTS)
2580  mysql->client_flag|= CLIENT_MULTI_RESULTS;
2581 
2582 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
2583  if (mysql->options.ssl_key || mysql->options.ssl_cert ||
2584  mysql->options.ssl_ca || mysql->options.ssl_capath ||
2585  mysql->options.ssl_cipher ||
2586  (mysql->options.extension && mysql->options.extension->ssl_crl) ||
2587  (mysql->options.extension && mysql->options.extension->ssl_crlpath))
2588  mysql->options.use_ssl= 1;
2589  if (mysql->options.use_ssl)
2590  mysql->client_flag|= CLIENT_SSL;
2591 #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY*/
2592  if (mpvio->db)
2593  mysql->client_flag|= CLIENT_CONNECT_WITH_DB;
2594 
2595  /* Remove options that server doesn't support */
2596  mysql->client_flag= mysql->client_flag &
2597  (~(CLIENT_COMPRESS | CLIENT_SSL | CLIENT_PROTOCOL_41)
2598  | mysql->server_capabilities);
2599 
2600 #ifndef HAVE_COMPRESS
2601  mysql->client_flag&= ~CLIENT_COMPRESS;
2602 #endif
2603 
2604  if (mysql->client_flag & CLIENT_PROTOCOL_41)
2605  {
2606  /* 4.1 server and 4.1 client has a 32 byte option flag */
2607  int4store(buff,mysql->client_flag);
2608  int4store(buff+4, net->max_packet_size);
2609  buff[8]= (char) mysql->charset->number;
2610  memset(buff+9, 0, 32-9);
2611  end= buff+32;
2612  }
2613  else
2614  {
2615  int2store(buff, mysql->client_flag);
2616  int3store(buff+2, net->max_packet_size);
2617  end= buff+5;
2618  }
2619 #ifdef HAVE_OPENSSL
2620  if (mysql->client_flag & CLIENT_SSL)
2621  {
2622  /* Do the SSL layering. */
2623  struct st_mysql_options *options= &mysql->options;
2624  struct st_VioSSLFd *ssl_fd;
2625  enum enum_ssl_init_error ssl_init_error;
2626  const char *cert_error;
2627  unsigned long ssl_error;
2628 
2629  /*
2630  Send mysql->client_flag, max_packet_size - unencrypted otherwise
2631  the server does not know we want to do SSL
2632  */
2633  if (my_net_write(net, (uchar*)buff, (size_t) (end-buff)) || net_flush(net))
2634  {
2635  set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
2636  ER(CR_SERVER_LOST_EXTENDED),
2637  "sending connection information to server",
2638  errno);
2639  goto error;
2640  }
2641 
2642  /* Create the VioSSLConnectorFd - init SSL and load certs */
2643  if (!(ssl_fd= new_VioSSLConnectorFd(options->ssl_key,
2644  options->ssl_cert,
2645  options->ssl_ca,
2646  options->ssl_capath,
2647  options->ssl_cipher,
2648  &ssl_init_error,
2649  options->extension ?
2650  options->extension->ssl_crl : NULL,
2651  options->extension ?
2652  options->extension->ssl_crlpath : NULL)))
2653  {
2654  set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
2655  ER(CR_SSL_CONNECTION_ERROR), sslGetErrString(ssl_init_error));
2656  goto error;
2657  }
2658  mysql->connector_fd= (unsigned char *) ssl_fd;
2659 
2660  /* Connect to the server */
2661  DBUG_PRINT("info", ("IO layer change in progress..."));
2662  if (sslconnect(ssl_fd, net->vio,
2663  (long) (mysql->options.connect_timeout), &ssl_error))
2664  {
2665  char buf[512];
2666  ERR_error_string_n(ssl_error, buf, 512);
2667  buf[511]= 0;
2668  set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
2669  ER(CR_SSL_CONNECTION_ERROR),
2670  buf);
2671  goto error;
2672  }
2673  DBUG_PRINT("info", ("IO layer change done!"));
2674 
2675  /* Verify server cert */
2676  if ((mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) &&
2677  ssl_verify_server_cert(net->vio, mysql->host, &cert_error))
2678  {
2679  set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
2680  ER(CR_SSL_CONNECTION_ERROR), cert_error);
2681  goto error;
2682  }
2683  }
2684 #endif /* HAVE_OPENSSL */
2685 
2686  DBUG_PRINT("info",("Server version = '%s' capabilites: %lu status: %u client_flag: %lu",
2687  mysql->server_version, mysql->server_capabilities,
2688  mysql->server_status, mysql->client_flag));
2689 
2690  compile_time_assert(MYSQL_USERNAME_LENGTH == USERNAME_LENGTH);
2691 
2692  /* This needs to be changed as it's not useful with big packets */
2693  if (mysql->user[0])
2694  strmake(end, mysql->user, USERNAME_LENGTH);
2695  else
2696  read_user_name(end);
2697 
2698  /* We have to handle different version of handshake here */
2699  DBUG_PRINT("info",("user: %s",end));
2700  end= strend(end) + 1;
2701  if (data_len)
2702  {
2703  if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
2704  {
2705  /*
2706  Since the older versions of server do not have
2707  CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA capability,
2708  a check is performed on this before sending auth data.
2709  If lenenc support is not available, the data is sent
2710  in the format of first byte representing the length of
2711  the string followed by the actual string.
2712  */
2713  if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA)
2714  end= write_length_encoded_string4(end, (char *)(buff + buff_size),
2715  (char *) data,
2716  (char *)(data + data_len));
2717  else
2718  end= write_string(end, (char *)(buff + buff_size),
2719  (char *) data,
2720  (char *)(data + data_len));
2721  if (end == NULL)
2722  goto error;
2723  }
2724  else
2725  {
2726  DBUG_ASSERT(data_len == SCRAMBLE_LENGTH_323 + 1); /* incl. \0 at the end */
2727  memcpy(end, data, data_len);
2728  end+= data_len;
2729  }
2730  }
2731  else
2732  *end++= 0;
2733 
2734  /* Add database if needed */
2735  if (mpvio->db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
2736  {
2737  end= strmake(end, mpvio->db, NAME_LEN) + 1;
2738  mysql->db= my_strdup(mpvio->db, MYF(MY_WME));
2739  }
2740 
2741  if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
2742  end= strmake(end, mpvio->plugin->name, NAME_LEN) + 1;
2743 
2744  end= (char *) send_client_connect_attrs(mysql, (uchar *) end);
2745 
2746  /* Write authentication package */
2747  if (my_net_write(net, (uchar*) buff, (size_t) (end-buff)) || net_flush(net))
2748  {
2749  set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
2750  ER(CR_SERVER_LOST_EXTENDED),
2751  "sending authentication information",
2752  errno);
2753  goto error;
2754  }
2755  my_afree(buff);
2756  return 0;
2757 
2758 error:
2759  my_afree(buff);
2760  return 1;
2761 }
2762 
2769 static int client_mpvio_read_packet(struct st_plugin_vio *mpv, uchar **buf)
2770 {
2771  MCPVIO_EXT *mpvio= (MCPVIO_EXT*)mpv;
2772  MYSQL *mysql= mpvio->mysql;
2773  ulong pkt_len;
2774 
2775  /* there are cached data left, feed it to a plugin */
2776  if (mpvio->cached_server_reply.pkt)
2777  {
2778  *buf= mpvio->cached_server_reply.pkt;
2779  mpvio->cached_server_reply.pkt= 0;
2780  mpvio->packets_read++;
2781  return mpvio->cached_server_reply.pkt_len;
2782  }
2783 
2784  if (mpvio->packets_read == 0)
2785  {
2786  /*
2787  the server handshake packet came from the wrong plugin,
2788  or it's mysql_change_user(). Either way, there is no data
2789  for a plugin to read. send a dummy packet to the server
2790  to initiate a dialog.
2791  */
2792  if (client_mpvio_write_packet(mpv, 0, 0))
2793  return (int)packet_error;
2794  }
2795 
2796  /* otherwise read the data */
2797  pkt_len= (*mysql->methods->read_change_user_result)(mysql);
2798  mpvio->last_read_packet_len= pkt_len;
2799  *buf= mysql->net.read_pos;
2800 
2801  /* was it a request to change plugins ? */
2802  if (**buf == 254)
2803  return (int)packet_error; /* if yes, this plugin shan't continue */
2804 
2805  /*
2806  the server sends \1\255 or \1\254 instead of just \255 or \254 -
2807  for us to not confuse it with an error or "change plugin" packets.
2808  We remove this escaping \1 here.
2809 
2810  See also server_mpvio_write_packet() where the escaping is done.
2811  */
2812  if (pkt_len && **buf == 1)
2813  {
2814  (*buf)++;
2815  pkt_len--;
2816  }
2817  mpvio->packets_read++;
2818  return pkt_len;
2819 }
2820 
2830 static int client_mpvio_write_packet(struct st_plugin_vio *mpv,
2831  const uchar *pkt, int pkt_len)
2832 {
2833  int res;
2834  MCPVIO_EXT *mpvio= (MCPVIO_EXT*)mpv;
2835 
2836  if (mpvio->packets_written == 0)
2837  {
2838  if (mpvio->mysql_change_user)
2839  res= send_change_user_packet(mpvio, pkt, pkt_len);
2840  else
2841  res= send_client_reply_packet(mpvio, pkt, pkt_len);
2842  }
2843  else
2844  {
2845  NET *net= &mpvio->mysql->net;
2846  if (mpvio->mysql->thd)
2847  res= 1; /* no chit-chat in embedded */
2848  else
2849  res= my_net_write(net, pkt, pkt_len) || net_flush(net);
2850  if (res)
2851  set_mysql_extended_error(mpvio->mysql, CR_SERVER_LOST, unknown_sqlstate,
2852  ER(CR_SERVER_LOST_EXTENDED),
2853  "sending authentication information",
2854  errno);
2855  }
2856  mpvio->packets_written++;
2857  return res;
2858 }
2859 
2864 void mpvio_info(Vio *vio, MYSQL_PLUGIN_VIO_INFO *info)
2865 {
2866  memset(info, 0, sizeof(*info));
2867  switch (vio->type) {
2868  case VIO_TYPE_TCPIP:
2869  info->protocol= MYSQL_VIO_TCP;
2870  info->socket= vio_fd(vio);
2871  return;
2872  case VIO_TYPE_SOCKET:
2873  info->protocol= MYSQL_VIO_SOCKET;
2874  info->socket= vio_fd(vio);
2875  return;
2876  case VIO_TYPE_SSL:
2877  {
2878  struct sockaddr addr;
2879  socklen_t addrlen= sizeof(addr);
2880  if (getsockname(vio_fd(vio), &addr, &addrlen))
2881  return;
2882  info->protocol= addr.sa_family == AF_UNIX ?
2883  MYSQL_VIO_SOCKET : MYSQL_VIO_TCP;
2884  info->socket= vio_fd(vio);
2885  return;
2886  }
2887 #ifdef _WIN32
2888  case VIO_TYPE_NAMEDPIPE:
2889  info->protocol= MYSQL_VIO_PIPE;
2890  info->handle= vio->hPipe;
2891  return;
2892 #ifdef HAVE_SMEM
2893  case VIO_TYPE_SHARED_MEMORY:
2894  info->protocol= MYSQL_VIO_MEMORY;
2895  info->handle= vio->handle_file_map; /* or what ? */
2896  return;
2897 #endif
2898 #endif
2899  default: DBUG_ASSERT(0);
2900  }
2901 }
2902 
2903 static void client_mpvio_info(MYSQL_PLUGIN_VIO *vio,
2904  MYSQL_PLUGIN_VIO_INFO *info)
2905 {
2906  MCPVIO_EXT *mpvio= (MCPVIO_EXT*)vio;
2907  mpvio_info(mpvio->mysql->net.vio, info);
2908 }
2909 
2910 
2911 my_bool libmysql_cleartext_plugin_enabled= 0;
2912 
2913 static my_bool check_plugin_enabled(MYSQL *mysql, auth_plugin_t *plugin)
2914 {
2915  if (plugin == &clear_password_client_plugin &&
2916  (!libmysql_cleartext_plugin_enabled &&
2917  (!mysql->options.extension ||
2918  !mysql->options.extension->enable_cleartext_plugin)))
2919  {
2920  set_mysql_extended_error(mysql, CR_AUTH_PLUGIN_CANNOT_LOAD,
2921  unknown_sqlstate,
2922  ER(CR_AUTH_PLUGIN_CANNOT_LOAD),
2923  clear_password_client_plugin.name,
2924  "plugin not enabled");
2925  return TRUE;
2926  }
2927  return FALSE;
2928 }
2929 
2930 
2947 int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
2948  const char *data_plugin, const char *db)
2949 {
2950  const char *auth_plugin_name;
2951  auth_plugin_t *auth_plugin;
2952  MCPVIO_EXT mpvio;
2953  ulong pkt_length;
2954  int res;
2955 
2956  DBUG_ENTER ("run_plugin_auth");
2957  /* determine the default/initial plugin to use */
2958  if (mysql->options.extension && mysql->options.extension->default_auth &&
2959  mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
2960  {
2961  auth_plugin_name= mysql->options.extension->default_auth;
2962  if (!(auth_plugin= (auth_plugin_t*) mysql_client_find_plugin(mysql,
2963  auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN)))
2964  DBUG_RETURN (1); /* oops, not found */
2965  }
2966  else
2967  {
2968  auth_plugin= mysql->server_capabilities & CLIENT_PROTOCOL_41 ?
2969  &native_password_client_plugin : &old_password_client_plugin;
2970  auth_plugin_name= auth_plugin->name;
2971  }
2972 
2973  if (check_plugin_enabled(mysql, auth_plugin))
2974  DBUG_RETURN(1);
2975 
2976  DBUG_PRINT ("info", ("using plugin %s", auth_plugin_name));
2977 
2978  mysql->net.last_errno= 0; /* just in case */
2979 
2980  if (data_plugin && strcmp(data_plugin, auth_plugin_name))
2981  {
2982  /* data was prepared for a different plugin, don't show it to this one */
2983  data= 0;
2984  data_len= 0;
2985  }
2986 
2987  mpvio.mysql_change_user= data_plugin == 0;
2988  mpvio.cached_server_reply.pkt= (uchar*)data;
2989  mpvio.cached_server_reply.pkt_len= data_len;
2990  mpvio.read_packet= client_mpvio_read_packet;
2991  mpvio.write_packet= client_mpvio_write_packet;
2992  mpvio.info= client_mpvio_info;
2993  mpvio.mysql= mysql;
2994  mpvio.packets_read= mpvio.packets_written= 0;
2995  mpvio.db= db;
2996  mpvio.plugin= auth_plugin;
2997 
2998  res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql);
2999  DBUG_PRINT ("info", ("authenticate_user returned %s",
3000  res == CR_OK ? "CR_OK" :
3001  res == CR_ERROR ? "CR_ERROR" :
3002  res == CR_OK_HANDSHAKE_COMPLETE ?
3003  "CR_OK_HANDSHAKE_COMPLETE" : "error"));
3004 
3005  compile_time_assert(CR_OK == -1);
3006  compile_time_assert(CR_ERROR == 0);
3007 
3008  /*
3009  The connection may be closed. If so: do not try to read from the buffer.
3010  */
3011  if (res > CR_OK &&
3012  (!my_net_is_inited(&mysql->net) || mysql->net.read_pos[0] != 254))
3013  {
3014  /*
3015  the plugin returned an error. write it down in mysql,
3016  unless the error code is CR_ERROR and mysql->net.last_errno
3017  is already set (the plugin has done it)
3018  */
3019  DBUG_PRINT ("info", ("res=%d", res));
3020  if (res > CR_ERROR)
3021  set_mysql_error(mysql, res, unknown_sqlstate);
3022  else
3023  if (!mysql->net.last_errno)
3024  set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
3025  DBUG_RETURN (1);
3026  }
3027 
3028  /* read the OK packet (or use the cached value in mysql->net.read_pos */
3029  if (res == CR_OK)
3030  pkt_length= (*mysql->methods->read_change_user_result)(mysql);
3031  else /* res == CR_OK_HANDSHAKE_COMPLETE */
3032  pkt_length= mpvio.last_read_packet_len;
3033 
3034  DBUG_PRINT ("info", ("OK packet length=%lu", pkt_length));
3035  if (pkt_length == packet_error)
3036  {
3037  if (mysql->net.last_errno == CR_SERVER_LOST)
3038  set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
3039  ER(CR_SERVER_LOST_EXTENDED),
3040  "reading authorization packet",
3041  errno);
3042  DBUG_RETURN (1);
3043  }
3044 
3045  if (mysql->net.read_pos[0] == 254)
3046  {
3047  /* The server asked to use a different authentication plugin */
3048  if (pkt_length == 1)
3049  {
3050  /* old "use short scramble" packet */
3051  DBUG_PRINT ("info", ("old use short scramble packet from server"));
3052  auth_plugin_name= old_password_plugin_name;
3053  mpvio.cached_server_reply.pkt= (uchar*)mysql->scramble;
3054  mpvio.cached_server_reply.pkt_len= SCRAMBLE_LENGTH + 1;
3055  }
3056  else
3057  {
3058  /* new "use different plugin" packet */
3059  uint len;
3060  auth_plugin_name= (char*)mysql->net.read_pos + 1;
3061  len= strlen(auth_plugin_name); /* safe as my_net_read always appends \0 */
3062  mpvio.cached_server_reply.pkt_len= pkt_length - len - 2;
3063  mpvio.cached_server_reply.pkt= mysql->net.read_pos + len + 2;
3064  DBUG_PRINT ("info", ("change plugin packet from server for plugin %s",
3065  auth_plugin_name));
3066  }
3067 
3068  if (!(auth_plugin= (auth_plugin_t *) mysql_client_find_plugin(mysql,
3069  auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN)))
3070  DBUG_RETURN (1);
3071 
3072  if (check_plugin_enabled(mysql, auth_plugin))
3073  DBUG_RETURN(1);
3074 
3075  mpvio.plugin= auth_plugin;
3076  res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql);
3077 
3078  DBUG_PRINT ("info", ("second authenticate_user returned %s",
3079  res == CR_OK ? "CR_OK" :
3080  res == CR_ERROR ? "CR_ERROR" :
3081  res == CR_OK_HANDSHAKE_COMPLETE ?
3082  "CR_OK_HANDSHAKE_COMPLETE" : "error"));
3083  if (res > CR_OK)
3084  {
3085  if (res > CR_ERROR)
3086  set_mysql_error(mysql, res, unknown_sqlstate);
3087  else
3088  if (!mysql->net.last_errno)
3089  set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
3090  DBUG_RETURN (1);
3091  }
3092 
3093  if (res != CR_OK_HANDSHAKE_COMPLETE)
3094  {
3095  /* Read what server thinks about out new auth message report */
3096  if (cli_safe_read(mysql) == packet_error)
3097  {
3098  if (mysql->net.last_errno == CR_SERVER_LOST)
3099  set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
3100  ER(CR_SERVER_LOST_EXTENDED),
3101  "reading final connect information",
3102  errno);
3103  DBUG_RETURN (1);
3104  }
3105  }
3106  }
3107  /*
3108  net->read_pos[0] should always be 0 here if the server implements
3109  the protocol correctly
3110  */
3111  DBUG_RETURN (mysql->net.read_pos[0] != 0);
3112 }
3113 
3114 
3116 static int
3117 set_connect_attributes(MYSQL *mysql, char *buff, size_t buf_len)
3118 {
3119  int rc= 0;
3120 
3121  /*
3122  Clean up any values set by the client code. We want these options as
3123  consistent as possible
3124  */
3125  rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_client_name");
3126  rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_os");
3127  rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_platform");
3128  rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_pid");
3129  rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_thread");
3130  rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_client_version");
3131 
3132  /*
3133  Now let's set up some values
3134  */
3135  rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
3136  "_client_name", "libmysql");
3137  rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
3138  "_client_version", PACKAGE_VERSION);
3139  rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
3140  "_os", SYSTEM_TYPE);
3141  rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
3142  "_platform", MACHINE_TYPE);
3143 #ifdef __WIN__
3144  snprintf(buff, buf_len, "%lu", (ulong) GetCurrentProcessId());
3145 #else
3146  snprintf(buff, buf_len, "%lu", (ulong) getpid());
3147 #endif
3148  rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_pid", buff);
3149 
3150 #ifdef __WIN__
3151  snprintf(buff, buf_len, "%lu", (ulong) GetCurrentThreadId());
3152  rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_thread", buff);
3153 #endif
3154 
3155  return rc > 0 ? 1 : 0;
3156 }
3157 
3158 
3159 MYSQL * STDCALL
3160 CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
3161  const char *passwd, const char *db,
3162  uint port, const char *unix_socket,ulong client_flag)
3163 {
3164  char buff[NAME_LEN+USERNAME_LENGTH+100];
3165  int scramble_data_len, pkt_scramble_len= 0;
3166  char *end,*host_info= 0, *server_version_end, *pkt_end;
3167  char *scramble_data;
3168  const char *scramble_plugin;
3169  ulong pkt_length;
3170  NET *net= &mysql->net;
3171 #ifdef __WIN__
3172  HANDLE hPipe=INVALID_HANDLE_VALUE;
3173 #endif
3174 #ifdef HAVE_SYS_UN_H
3175  struct sockaddr_un UNIXaddr;
3176 #endif
3177  DBUG_ENTER("mysql_real_connect");
3178 
3179  DBUG_PRINT("enter",("host: %s db: %s user: %s (client)",
3180  host ? host : "(Null)",
3181  db ? db : "(Null)",
3182  user ? user : "(Null)"));
3183 
3184  /* Test whether we're already connected */
3185  if (net->vio)
3186  {
3187  set_mysql_error(mysql, CR_ALREADY_CONNECTED, unknown_sqlstate);
3188  DBUG_RETURN(0);
3189  }
3190 
3191  if (set_connect_attributes(mysql, buff, sizeof(buff)))
3192  DBUG_RETURN(0);
3193 
3194  mysql->methods= &client_methods;
3195  net->vio = 0; /* If something goes wrong */
3196  mysql->client_flag=0; /* For handshake */
3197 
3198  /* use default options */
3199  if (mysql->options.my_cnf_file || mysql->options.my_cnf_group)
3200  {
3201  mysql_read_default_options(&mysql->options,
3202  (mysql->options.my_cnf_file ?
3203  mysql->options.my_cnf_file : "my"),
3204  mysql->options.my_cnf_group);
3205  my_free(mysql->options.my_cnf_file);
3206  my_free(mysql->options.my_cnf_group);
3207  mysql->options.my_cnf_file=mysql->options.my_cnf_group=0;
3208  }
3209 
3210  /* Some empty-string-tests are done because of ODBC */
3211  if (!host || !host[0])
3212  host=mysql->options.host;
3213  if (!user || !user[0])
3214  {
3215  user=mysql->options.user;
3216  if (!user)
3217  user= "";
3218  }
3219  if (!passwd)
3220  {
3221  passwd=mysql->options.password;
3222 #if !defined(DONT_USE_MYSQL_PWD) && !defined(MYSQL_SERVER)
3223  if (!passwd)
3224  passwd=getenv("MYSQL_PWD"); /* get it from environment */
3225 #endif
3226  if (!passwd)
3227  passwd= "";
3228  }
3229  if (!db || !db[0])
3230  db=mysql->options.db;
3231  if (!port)
3232  port=mysql->options.port;
3233  if (!unix_socket)
3234  unix_socket=mysql->options.unix_socket;
3235 
3236  mysql->server_status=SERVER_STATUS_AUTOCOMMIT;
3237  DBUG_PRINT("info", ("Connecting"));
3238 
3239  /*
3240  Part 0: Grab a socket and connect it to the server
3241  */
3242 #if defined(HAVE_SMEM)
3243  if ((!mysql->options.protocol ||
3244  mysql->options.protocol == MYSQL_PROTOCOL_MEMORY) &&
3245  (!host || !strcmp(host,LOCAL_HOST)))
3246  {
3247  HANDLE handle_map;
3248  DBUG_PRINT("info", ("Using shared memory"));
3249 
3250  handle_map= create_shared_memory(mysql, net,
3251  get_win32_connect_timeout(mysql));
3252 
3253  if (handle_map == INVALID_HANDLE_VALUE)
3254  {
3255  DBUG_PRINT("error",
3256  ("host: '%s' socket: '%s' shared memory: %s have_tcpip: %d",
3257  host ? host : "<null>",
3258  unix_socket ? unix_socket : "<null>",
3259  (int) mysql->options.shared_memory_base_name,
3260  (int) have_tcpip));
3261  if (mysql->options.protocol == MYSQL_PROTOCOL_MEMORY)
3262  goto error;
3263 
3264  /*
3265  Try also with PIPE or TCP/IP. Clear the error from
3266  create_shared_memory().
3267  */
3268 
3269  net_clear_error(net);
3270  }
3271  else
3272  {
3273  mysql->options.protocol=MYSQL_PROTOCOL_MEMORY;
3274  unix_socket = 0;
3275  host=mysql->options.shared_memory_base_name;
3276  my_snprintf(host_info=buff, sizeof(buff)-1,
3277  ER(CR_SHARED_MEMORY_CONNECTION), host);
3278  }
3279  }
3280 #endif /* HAVE_SMEM */
3281 #if defined(HAVE_SYS_UN_H)
3282  if (!net->vio &&
3283  (!mysql->options.protocol ||
3284  mysql->options.protocol == MYSQL_PROTOCOL_SOCKET) &&
3285  (unix_socket || mysql_unix_port) &&
3286  (!host || !strcmp(host,LOCAL_HOST)))
3287  {
3288  my_socket sock= socket(AF_UNIX, SOCK_STREAM, 0);
3289  DBUG_PRINT("info", ("Using socket"));
3290  if (sock == SOCKET_ERROR)
3291  {
3292  set_mysql_extended_error(mysql, CR_SOCKET_CREATE_ERROR,
3293  unknown_sqlstate,
3294  ER(CR_SOCKET_CREATE_ERROR),
3295  socket_errno);
3296  goto error;
3297  }
3298 
3299  net->vio= vio_new(sock, VIO_TYPE_SOCKET,
3300  VIO_LOCALHOST | VIO_BUFFERED_READ);
3301  if (!net->vio)
3302  {
3303  DBUG_PRINT("error",("Unknow protocol %d ", mysql->options.protocol));
3304  set_mysql_error(mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate);
3305  closesocket(sock);
3306  goto error;
3307  }
3308 
3309  host= LOCAL_HOST;
3310  if (!unix_socket)
3311  unix_socket= mysql_unix_port;
3312  host_info= (char*) ER(CR_LOCALHOST_CONNECTION);
3313  DBUG_PRINT("info", ("Using UNIX sock '%s'", unix_socket));
3314 
3315  memset(&UNIXaddr, 0, sizeof(UNIXaddr));
3316  UNIXaddr.sun_family= AF_UNIX;
3317  strmake(UNIXaddr.sun_path, unix_socket, sizeof(UNIXaddr.sun_path)-1);
3318 
3319  if (vio_socket_connect(net->vio, (struct sockaddr *) &UNIXaddr,
3320  sizeof(UNIXaddr), get_vio_connect_timeout(mysql)))
3321  {
3322  DBUG_PRINT("error",("Got error %d on connect to local server",
3323  socket_errno));
3324  set_mysql_extended_error(mysql, CR_CONNECTION_ERROR,
3325  unknown_sqlstate,
3326  ER(CR_CONNECTION_ERROR),
3327  unix_socket, socket_errno);
3328  vio_delete(net->vio);
3329  net->vio= 0;
3330  goto error;
3331  }
3332  mysql->options.protocol=MYSQL_PROTOCOL_SOCKET;
3333  }
3334 #elif defined(_WIN32)
3335  if (!net->vio &&
3336  (mysql->options.protocol == MYSQL_PROTOCOL_PIPE ||
3337  (host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) ||
3338  (! have_tcpip && (unix_socket || !host && is_NT()))))
3339  {
3340  hPipe= create_named_pipe(mysql, get_win32_connect_timeout(mysql),
3341  &host, &unix_socket);
3342 
3343  if (hPipe == INVALID_HANDLE_VALUE)
3344  {
3345  DBUG_PRINT("error",
3346  ("host: '%s' socket: '%s' have_tcpip: %d",
3347  host ? host : "<null>",
3348  unix_socket ? unix_socket : "<null>",
3349  (int) have_tcpip));
3350  if (mysql->options.protocol == MYSQL_PROTOCOL_PIPE ||
3351  (host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) ||
3352  (unix_socket && !strcmp(unix_socket,MYSQL_NAMEDPIPE)))
3353  goto error;
3354  /* Try also with TCP/IP */
3355  }
3356  else
3357  {
3358  net->vio= vio_new_win32pipe(hPipe);
3359  my_snprintf(host_info=buff, sizeof(buff)-1,
3360  ER(CR_NAMEDPIPE_CONNECTION), unix_socket);
3361  }
3362  }
3363 #endif
3364  DBUG_PRINT("info", ("net->vio: %p protocol: %d",
3365  net->vio, mysql->options.protocol));
3366  if (!net->vio &&
3367  (!mysql->options.protocol ||
3368  mysql->options.protocol == MYSQL_PROTOCOL_TCP))
3369  {
3370  struct addrinfo *res_lst, *client_bind_ai_lst= NULL, hints, *t_res;
3371  char port_buf[NI_MAXSERV];
3372  my_socket sock= SOCKET_ERROR;
3373  int gai_errno, saved_error= 0, status= -1, bind_result= 0;
3374  uint flags= VIO_BUFFERED_READ;
3375 
3376  unix_socket=0; /* This is not used */
3377 
3378  if (!port)
3379  port= mysql_port;
3380 
3381  if (!host)
3382  host= LOCAL_HOST;
3383 
3384  my_snprintf(host_info=buff, sizeof(buff)-1, ER(CR_TCP_CONNECTION), host);
3385  DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host, port));
3386 
3387  memset(&hints, 0, sizeof(hints));
3388  hints.ai_socktype= SOCK_STREAM;
3389  hints.ai_protocol= IPPROTO_TCP;
3390  hints.ai_family= AF_UNSPEC;
3391 
3392  DBUG_PRINT("info",("IPV6 getaddrinfo %s", host));
3393  my_snprintf(port_buf, NI_MAXSERV, "%d", port);
3394  gai_errno= getaddrinfo(host, port_buf, &hints, &res_lst);
3395 
3396  if (gai_errno != 0)
3397  {
3398  /*
3399  For DBUG we are keeping the right message but for client we default to
3400  historical error message.
3401  */
3402  DBUG_PRINT("info",("IPV6 getaddrinfo error %d", gai_errno));
3403  set_mysql_extended_error(mysql, CR_UNKNOWN_HOST, unknown_sqlstate,
3404  ER(CR_UNKNOWN_HOST), host, errno);
3405 
3406  goto error;
3407  }
3408 
3409  /* Get address info for client bind name if it is provided */
3410  if (mysql->options.ci.bind_address)
3411  {
3412  int bind_gai_errno= 0;
3413 
3414  DBUG_PRINT("info",("Resolving addresses for client bind: '%s'",
3415  mysql->options.ci.bind_address));
3416  /* Lookup address info for name */
3417  bind_gai_errno= getaddrinfo(mysql->options.ci.bind_address, 0,
3418  &hints, &client_bind_ai_lst);
3419  if (bind_gai_errno)
3420  {
3421  DBUG_PRINT("info",("client bind getaddrinfo error %d", bind_gai_errno));
3422  set_mysql_extended_error(mysql, CR_UNKNOWN_HOST, unknown_sqlstate,
3423  ER(CR_UNKNOWN_HOST),
3424  mysql->options.ci.bind_address,
3425  bind_gai_errno);
3426 
3427  freeaddrinfo(res_lst);
3428  goto error;
3429  }
3430  DBUG_PRINT("info", (" got address info for client bind name"));
3431  }
3432 
3433  /*
3434  A hostname might map to multiple IP addresses (IPv4/IPv6). Go over the
3435  list of IP addresses until a successful connection can be established.
3436  For each IP address, attempt to bind the socket to each client address
3437  for the client-side bind hostname until the bind is successful.
3438  */
3439  DBUG_PRINT("info", ("Try connect on all addresses for host."));
3440  for (t_res= res_lst; t_res; t_res= t_res->ai_next)
3441  {
3442  DBUG_PRINT("info", ("Create socket, family: %d type: %d proto: %d",
3443  t_res->ai_family, t_res->ai_socktype,
3444  t_res->ai_protocol));
3445 
3446  sock= socket(t_res->ai_family, t_res->ai_socktype, t_res->ai_protocol);
3447  if (sock == SOCKET_ERROR)
3448  {
3449  DBUG_PRINT("info", ("Socket created was invalid"));
3450  /* Try next address if there is one */
3451  saved_error= socket_errno;
3452  continue;
3453  }
3454 
3455  if (client_bind_ai_lst)
3456  {
3457  struct addrinfo* curr_bind_ai= NULL;
3458  DBUG_PRINT("info", ("Attempting to bind socket to bind address(es)"));
3459 
3460  /*
3461  We'll attempt to bind to each of the addresses returned, until
3462  we find one that works.
3463  If none works, we'll try the next destination host address
3464  (if any)
3465  */
3466  curr_bind_ai= client_bind_ai_lst;
3467 
3468  while (curr_bind_ai != NULL)
3469  {
3470  /* Attempt to bind the socket to the given address */
3471  bind_result= bind(sock,
3472  curr_bind_ai->ai_addr,
3473  curr_bind_ai->ai_addrlen);
3474  if (!bind_result)
3475  break; /* Success */
3476 
3477  DBUG_PRINT("info", ("bind failed, attempting another bind address"));
3478  /* Problem with the bind, move to next address if present */
3479  curr_bind_ai= curr_bind_ai->ai_next;
3480  }
3481 
3482  if (bind_result)
3483  {
3484  /*
3485  Could not bind to any client-side address with this destination
3486  Try the next destination address (if any)
3487  */
3488  DBUG_PRINT("info", ("All bind attempts with this address failed"));
3489  saved_error= socket_errno;
3490  closesocket(sock);
3491  continue;
3492  }
3493  DBUG_PRINT("info", ("Successfully bound client side of socket"));
3494  }
3495 
3496  /* Create a new Vio object to abstract the socket. */
3497  if (!net->vio)
3498  {
3499  if (!(net->vio= vio_new(sock, VIO_TYPE_TCPIP, flags)))
3500  {
3501  set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
3502  closesocket(sock);
3503  freeaddrinfo(res_lst);
3504  if (client_bind_ai_lst)
3505  freeaddrinfo(client_bind_ai_lst);
3506  goto error;
3507  }
3508  }
3509  /* Just reinitialize if one is already allocated. */
3510  else if (vio_reset(net->vio, VIO_TYPE_TCPIP, sock, NULL, flags))
3511  {
3512  set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
3513  closesocket(sock);
3514  freeaddrinfo(res_lst);
3515  if (client_bind_ai_lst)
3516  freeaddrinfo(client_bind_ai_lst);
3517  goto error;
3518  }
3519 
3520  DBUG_PRINT("info", ("Connect socket"));
3521  status= vio_socket_connect(net->vio, t_res->ai_addr, t_res->ai_addrlen,
3522  get_vio_connect_timeout(mysql));
3523  /*
3524  Here we rely on vio_socket_connect() to return success only if
3525  the connect attempt was really successful. Otherwise we would
3526  stop trying another address, believing we were successful.
3527  */
3528  if (!status)
3529  break;
3530 
3531  /*
3532  Save either the socket error status or the error code of
3533  the failed vio_connection operation. It is necessary to
3534  avoid having it overwritten by later operations.
3535  */
3536  saved_error= socket_errno;
3537 
3538  DBUG_PRINT("info", ("No success, close socket, try next address."));
3539  closesocket(sock);
3540  }
3541  DBUG_PRINT("info",
3542  ("End of connect attempts, sock: %d status: %d error: %d",
3543  sock, status, saved_error));
3544 
3545  freeaddrinfo(res_lst);
3546  if (client_bind_ai_lst)
3547  freeaddrinfo(client_bind_ai_lst);
3548 
3549  if (sock == SOCKET_ERROR)
3550  {
3551  set_mysql_extended_error(mysql, CR_IPSOCK_ERROR, unknown_sqlstate,
3552  ER(CR_IPSOCK_ERROR), saved_error);
3553  goto error;
3554  }
3555 
3556  if (status)
3557  {
3558  DBUG_PRINT("error",("Got error %d on connect to '%s'", saved_error, host));
3559  set_mysql_extended_error(mysql, CR_CONN_HOST_ERROR, unknown_sqlstate,
3560  ER(CR_CONN_HOST_ERROR), host, saved_error);
3561  goto error;
3562  }
3563  }
3564 
3565  DBUG_PRINT("info", ("net->vio: %p", net->vio));
3566  if (!net->vio)
3567  {
3568  DBUG_PRINT("error",("Unknow protocol %d ",mysql->options.protocol));
3569  set_mysql_error(mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate);
3570  goto error;
3571  }
3572 
3573  if (my_net_init(net, net->vio))
3574  {
3575  vio_delete(net->vio);
3576  net->vio = 0;
3577  set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
3578  goto error;
3579  }
3580  vio_keepalive(net->vio,TRUE);
3581 
3582  /* If user set read_timeout, let it override the default */
3583  if (mysql->options.read_timeout)
3584  my_net_set_read_timeout(net, mysql->options.read_timeout);
3585 
3586  /* If user set write_timeout, let it override the default */
3587  if (mysql->options.write_timeout)
3588  my_net_set_write_timeout(net, mysql->options.write_timeout);
3589 
3590  if (mysql->options.max_allowed_packet)
3591  net->max_packet_size= mysql->options.max_allowed_packet;
3592 
3593  /* Get version info */
3594  mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */
3595  if (mysql->options.connect_timeout &&
3596  (vio_io_wait(net->vio, VIO_IO_EVENT_READ,
3597  get_vio_connect_timeout(mysql)) < 1))
3598  {
3599  set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
3600  ER(CR_SERVER_LOST_EXTENDED),
3601  "waiting for initial communication packet",
3602  socket_errno);
3603  goto error;
3604  }
3605 
3606  /*
3607  Part 1: Connection established, read and parse first packet
3608  */
3609  DBUG_PRINT("info", ("Read first packet."));
3610 
3611  if ((pkt_length=cli_safe_read(mysql)) == packet_error)
3612  {
3613  if (mysql->net.last_errno == CR_SERVER_LOST)
3614  set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
3615  ER(CR_SERVER_LOST_EXTENDED),
3616  "reading initial communication packet",
3617  socket_errno);
3618  goto error;
3619  }
3620  pkt_end= (char*)net->read_pos + pkt_length;
3621  /* Check if version of protocol matches current one */
3622  mysql->protocol_version= net->read_pos[0];
3623  DBUG_DUMP("packet",(uchar*) net->read_pos,10);
3624  DBUG_PRINT("info",("mysql protocol version %d, server=%d",
3625  PROTOCOL_VERSION, mysql->protocol_version));
3626  if (mysql->protocol_version != PROTOCOL_VERSION)
3627  {
3628  set_mysql_extended_error(mysql, CR_VERSION_ERROR, unknown_sqlstate,
3629  ER(CR_VERSION_ERROR), mysql->protocol_version,
3630  PROTOCOL_VERSION);
3631  goto error;
3632  }
3633  server_version_end= end= strend((char*) net->read_pos+1);
3634  mysql->thread_id=uint4korr(end+1);
3635  end+=5;
3636  /*
3637  Scramble is split into two parts because old clients do not understand
3638  long scrambles; here goes the first part.
3639  */
3640  scramble_data= end;
3641  scramble_data_len= SCRAMBLE_LENGTH_323 + 1;
3642  scramble_plugin= old_password_plugin_name;
3643  end+= scramble_data_len;
3644 
3645  if (pkt_end >= end + 1)
3646  mysql->server_capabilities=uint2korr(end);
3647  if (pkt_end >= end + 18)
3648  {
3649  /* New protocol with 16 bytes to describe server characteristics */
3650  mysql->server_language=end[2];
3651  mysql->server_status=uint2korr(end+3);
3652  mysql->server_capabilities|= uint2korr(end+5) << 16;
3653  pkt_scramble_len= end[7];
3654  if (pkt_scramble_len < 0)
3655  {
3656  set_mysql_error(mysql, CR_MALFORMED_PACKET,
3657  unknown_sqlstate); /* purecov: inspected */
3658  goto error;
3659  }
3660  }
3661  end+= 18;
3662 
3663  if (mysql->options.secure_auth && passwd[0] &&
3664  !(mysql->server_capabilities & CLIENT_SECURE_CONNECTION))
3665  {
3666  set_mysql_error(mysql, CR_SECURE_AUTH, unknown_sqlstate);
3667  goto error;
3668  }
3669 
3670  if (mysql_init_character_set(mysql))
3671  goto error;
3672 
3673  /* Save connection information */
3674  if (!my_multi_malloc(MYF(0),
3675  &mysql->host_info, (uint) strlen(host_info)+1,
3676  &mysql->host, (uint) strlen(host)+1,
3677  &mysql->unix_socket,unix_socket ?
3678  (uint) strlen(unix_socket)+1 : (uint) 1,
3679  &mysql->server_version,
3680  (uint) (server_version_end - (char*) net->read_pos + 1),
3681  NullS) ||
3682  !(mysql->user=my_strdup(user,MYF(0))) ||
3683  !(mysql->passwd=my_strdup(passwd,MYF(0))))
3684  {
3685  set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
3686  goto error;
3687  }
3688  strmov(mysql->host_info,host_info);
3689  strmov(mysql->host,host);
3690  if (unix_socket)
3691  strmov(mysql->unix_socket,unix_socket);
3692  else
3693  mysql->unix_socket=0;
3694  strmov(mysql->server_version,(char*) net->read_pos+1);
3695  mysql->port=port;
3696 
3697  if (pkt_end >= end + SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1)
3698  {
3699  /*
3700  move the first scramble part - directly in the NET buffer -
3701  to get a full continuous scramble. We've read all the header,
3702  and can overwrite it now.
3703  */
3704  memmove(end - SCRAMBLE_LENGTH_323, scramble_data,
3705  SCRAMBLE_LENGTH_323);
3706  scramble_data= end - SCRAMBLE_LENGTH_323;
3707  if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
3708  {
3709  scramble_data_len= pkt_scramble_len;
3710  scramble_plugin= scramble_data + scramble_data_len;
3711  if (scramble_data + scramble_data_len > pkt_end)
3712  scramble_data_len= pkt_end - scramble_data;
3713  }
3714  else
3715  {
3716  scramble_data_len= pkt_end - scramble_data;
3717  scramble_plugin= native_password_plugin_name;
3718  }
3719  }
3720  else
3721  mysql->server_capabilities&= ~CLIENT_SECURE_CONNECTION;
3722 
3723  mysql->client_flag= client_flag;
3724 
3725  /*
3726  Part 2: invoke the plugin to send the authentication data to the server
3727  */
3728 
3729  if (run_plugin_auth(mysql, scramble_data, scramble_data_len,
3730  scramble_plugin, db))
3731  goto error;
3732 
3733  /*
3734  Part 3: authenticated, finish the initialization of the connection
3735  */
3736 
3737  if (mysql->client_flag & CLIENT_COMPRESS) /* We will use compression */
3738  net->compress=1;
3739 
3740 #ifdef CHECK_LICENSE
3741  if (check_license(mysql))
3742  goto error;
3743 #endif
3744 
3745  if (db && !mysql->db && mysql_select_db(mysql, db))
3746  {
3747  if (mysql->net.last_errno == CR_SERVER_LOST)
3748  set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
3749  ER(CR_SERVER_LOST_EXTENDED),
3750  "Setting intital database",
3751  errno);
3752  goto error;
3753  }
3754 
3755  /*
3756  Using init_commands is not supported when connecting from within the
3757  server.
3758  */
3759 #ifndef MYSQL_SERVER
3760  if (mysql->options.init_commands)
3761  {
3762  DYNAMIC_ARRAY *init_commands= mysql->options.init_commands;
3763  char **ptr= (char**)init_commands->buffer;
3764  char **end_command= ptr + init_commands->elements;
3765 
3766  my_bool reconnect=mysql->reconnect;
3767  mysql->reconnect=0;
3768 
3769  for (; ptr < end_command; ptr++)
3770  {
3771  int status;
3772 
3773  if (mysql_real_query(mysql,*ptr, (ulong) strlen(*ptr)))
3774  goto error;
3775 
3776  do {
3777  if (mysql->fields)
3778  {
3779  MYSQL_RES *res;
3780  if (!(res= cli_use_result(mysql)))
3781  goto error;
3782  mysql_free_result(res);
3783  }
3784  if ((status= mysql_next_result(mysql)) > 0)
3785  goto error;
3786  } while (status == 0);
3787  }
3788  mysql->reconnect=reconnect;
3789  }
3790 #endif
3791 
3792  DBUG_PRINT("exit", ("Mysql handler: 0x%lx", (long) mysql));
3793  DBUG_RETURN(mysql);
3794 
3795 error:
3796  DBUG_PRINT("error",("message: %u/%s (%s)",
3797  net->last_errno,
3798  net->sqlstate,
3799  net->last_error));
3800  {
3801  /* Free alloced memory */
3802  end_server(mysql);
3803  mysql_close_free(mysql);
3804  if (!(client_flag & CLIENT_REMEMBER_OPTIONS))
3805  mysql_close_free_options(mysql);
3806  }
3807  DBUG_RETURN(0);
3808 }
3809 
3810 
3811 my_bool mysql_reconnect(MYSQL *mysql)
3812 {
3813  MYSQL tmp_mysql;
3814  DBUG_ENTER("mysql_reconnect");
3815  DBUG_ASSERT(mysql);
3816  DBUG_PRINT("enter", ("mysql->reconnect: %d", mysql->reconnect));
3817 
3818  if (!mysql->reconnect ||
3819  (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info)
3820  {
3821  /* Allow reconnect next time */
3822  mysql->server_status&= ~SERVER_STATUS_IN_TRANS;
3823  set_mysql_error(mysql, CR_SERVER_GONE_ERROR, unknown_sqlstate);
3824  DBUG_RETURN(1);
3825  }
3826  mysql_init(&tmp_mysql);
3827  tmp_mysql.options= mysql->options;
3828  tmp_mysql.options.my_cnf_file= tmp_mysql.options.my_cnf_group= 0;
3829 
3830  if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
3831  mysql->db, mysql->port, mysql->unix_socket,
3832  mysql->client_flag | CLIENT_REMEMBER_OPTIONS))
3833  {
3834  memset(&tmp_mysql.options, 0, sizeof(tmp_mysql.options));
3835  mysql_close(&tmp_mysql);
3836  mysql->net.last_errno= tmp_mysql.net.last_errno;
3837  strmov(mysql->net.last_error, tmp_mysql.net.last_error);
3838  strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate);
3839  DBUG_RETURN(1);
3840  }
3841  if (mysql_set_character_set(&tmp_mysql, mysql->charset->csname))
3842  {
3843  DBUG_PRINT("error", ("mysql_set_character_set() failed"));
3844  memset(&tmp_mysql.options, 0, sizeof(tmp_mysql.options));
3845  mysql_close(&tmp_mysql);
3846  mysql->net.last_errno= tmp_mysql.net.last_errno;
3847  strmov(mysql->net.last_error, tmp_mysql.net.last_error);
3848  strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate);
3849  DBUG_RETURN(1);
3850  }
3851 
3852  DBUG_PRINT("info", ("reconnect succeded"));
3853  tmp_mysql.reconnect= 1;
3854  tmp_mysql.free_me= mysql->free_me;
3855 
3856  /* Move prepared statements (if any) over to the new mysql object */
3857  tmp_mysql.stmts= mysql->stmts;
3858  mysql->stmts= 0;
3859 
3860  /* Don't free options as these are now used in tmp_mysql */
3861  memset(&mysql->options, 0, sizeof(mysql->options));
3862  mysql->free_me=0;
3863  mysql_close(mysql);
3864  *mysql=tmp_mysql;
3865  net_clear(&mysql->net, 1);
3866  mysql->affected_rows= ~(my_ulonglong) 0;
3867  DBUG_RETURN(0);
3868 }
3869 
3870 
3871 /**************************************************************************
3872  Set current database
3873 **************************************************************************/
3874 
3875 int STDCALL
3876 mysql_select_db(MYSQL *mysql, const char *db)
3877 {
3878  int error;
3879  DBUG_ENTER("mysql_select_db");
3880  DBUG_PRINT("enter",("db: '%s'",db));
3881 
3882  if ((error=simple_command(mysql,COM_INIT_DB, (const uchar*) db,
3883  (ulong) strlen(db),0)))
3884  DBUG_RETURN(error);
3885  my_free(mysql->db);
3886  mysql->db=my_strdup(db,MYF(MY_WME));
3887  DBUG_RETURN(0);
3888 }
3889 
3890 
3891 /*************************************************************************
3892  Send a QUIT to the server and close the connection
3893  If handle is alloced by mysql connect free it.
3894 *************************************************************************/
3895 
3896 static void mysql_close_free_options(MYSQL *mysql)
3897 {
3898  DBUG_ENTER("mysql_close_free_options");
3899 
3900  my_free(mysql->options.user);
3901  my_free(mysql->options.host);
3902  my_free(mysql->options.password);
3903  my_free(mysql->options.unix_socket);
3904  my_free(mysql->options.db);
3905  my_free(mysql->options.my_cnf_file);
3906  my_free(mysql->options.my_cnf_group);
3907  my_free(mysql->options.charset_dir);
3908  my_free(mysql->options.charset_name);
3909  my_free(mysql->options.ci.client_ip);
3910  /* ci.bind_adress is union with client_ip, already freed above */
3911  if (mysql->options.init_commands)
3912  {
3913  DYNAMIC_ARRAY *init_commands= mysql->options.init_commands;
3914  char **ptr= (char**)init_commands->buffer;
3915  char **end= ptr + init_commands->elements;
3916  for (; ptr<end; ptr++)
3917  my_free(*ptr);
3918  delete_dynamic(init_commands);
3919  my_free(init_commands);
3920  }
3921 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
3922  mysql_ssl_free(mysql);
3923 #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
3924 #ifdef HAVE_SMEM
3925  if (mysql->options.shared_memory_base_name != def_shared_memory_base_name)
3926  my_free(mysql->options.shared_memory_base_name);
3927 #endif /* HAVE_SMEM */
3928  if (mysql->options.extension)
3929  {
3930  my_free(mysql->options.extension->plugin_dir);
3931  my_free(mysql->options.extension->default_auth);
3932  my_hash_free(&mysql->options.extension->connection_attributes);
3933  my_free(mysql->options.extension);
3934  }
3935  memset(&mysql->options, 0, sizeof(mysql->options));
3936  DBUG_VOID_RETURN;
3937 }
3938 
3939 
3940 static void mysql_close_free(MYSQL *mysql)
3941 {
3942  my_free(mysql->host_info);
3943  my_free(mysql->user);
3944  my_free(mysql->passwd);
3945  my_free(mysql->db);
3946 #if defined(EMBEDDED_LIBRARY) || MYSQL_VERSION_ID >= 50100
3947  my_free(mysql->info_buffer);
3948  mysql->info_buffer= 0;
3949 #endif
3950  /* Clear pointers for better safety */
3951  mysql->host_info= mysql->user= mysql->passwd= mysql->db= 0;
3952 }
3953 
3954 
3970 static void mysql_prune_stmt_list(MYSQL *mysql)
3971 {
3972  LIST *element= mysql->stmts;
3973  LIST *pruned_list= 0;
3974 
3975  for (; element; element= element->next)
3976  {
3977  MYSQL_STMT *stmt= (MYSQL_STMT *) element->data;
3978  if (stmt->state != MYSQL_STMT_INIT_DONE)
3979  {
3980  stmt->mysql= 0;
3981  stmt->last_errno= CR_SERVER_LOST;
3982  strmov(stmt->last_error, ER(CR_SERVER_LOST));
3983  strmov(stmt->sqlstate, unknown_sqlstate);
3984  }
3985  else
3986  {
3987  pruned_list= list_add(pruned_list, element);
3988  }
3989  }
3990 
3991  mysql->stmts= pruned_list;
3992 }
3993 
3994 
3995 /*
3996  Clear connection pointer of every statement: this is necessary
3997  to give error on attempt to use a prepared statement of closed
3998  connection.
3999 
4000  SYNOPSYS
4001  mysql_detach_stmt_list()
4002  stmt_list pointer to mysql->stmts
4003  func_name name of calling function
4004 
4005  NOTE
4006  There is similar code in mysql_reconnect(), so changes here
4007  should also be reflected there.
4008 */
4009 
4010 void mysql_detach_stmt_list(LIST **stmt_list __attribute__((unused)),
4011  const char *func_name __attribute__((unused)))
4012 {
4013 #ifdef MYSQL_CLIENT
4014  /* Reset connection handle in all prepared statements. */
4015  LIST *element= *stmt_list;
4016  char buff[MYSQL_ERRMSG_SIZE];
4017  DBUG_ENTER("mysql_detach_stmt_list");
4018 
4019  my_snprintf(buff, sizeof(buff)-1, ER(CR_STMT_CLOSED), func_name);
4020  for (; element; element= element->next)
4021  {
4022  MYSQL_STMT *stmt= (MYSQL_STMT *) element->data;
4023  set_stmt_error(stmt, CR_STMT_CLOSED, unknown_sqlstate, buff);
4024  stmt->mysql= 0;
4025  /* No need to call list_delete for statement here */
4026  }
4027  *stmt_list= 0;
4028  DBUG_VOID_RETURN;
4029 #endif /* MYSQL_CLIENT */
4030 }
4031 
4032 
4033 void STDCALL mysql_close(MYSQL *mysql)
4034 {
4035  DBUG_ENTER("mysql_close");
4036  if (mysql) /* Some simple safety */
4037  {
4038  /* If connection is still up, send a QUIT message */
4039  if (mysql->net.vio != 0)
4040  {
4041  free_old_query(mysql);
4042  mysql->status=MYSQL_STATUS_READY; /* Force command */
4043  mysql->reconnect=0;
4044  simple_command(mysql,COM_QUIT,(uchar*) 0,0,1);
4045  end_server(mysql); /* Sets mysql->net.vio= 0 */
4046  }
4047  mysql_close_free_options(mysql);
4048  mysql_close_free(mysql);
4049  mysql_detach_stmt_list(&mysql->stmts, "mysql_close");
4050 #ifndef MYSQL_SERVER
4051  if (mysql->thd)
4052  (*mysql->methods->free_embedded_thd)(mysql);
4053 #endif
4054  if (mysql->free_me)
4055  my_free(mysql);
4056  }
4057  DBUG_VOID_RETURN;
4058 }
4059 
4060 
4061 static my_bool cli_read_query_result(MYSQL *mysql)
4062 {
4063  uchar *pos;
4064  ulong field_count;
4065  MYSQL_DATA *fields;
4066  ulong length;
4067  DBUG_ENTER("cli_read_query_result");
4068 
4069  if ((length = cli_safe_read(mysql)) == packet_error)
4070  DBUG_RETURN(1);
4071  free_old_query(mysql); /* Free old result */
4072 #ifdef MYSQL_CLIENT /* Avoid warn of unused labels*/
4073 get_info:
4074 #endif
4075  pos=(uchar*) mysql->net.read_pos;
4076  if ((field_count= net_field_length(&pos)) == 0)
4077  {
4078  mysql->affected_rows= net_field_length_ll(&pos);
4079  mysql->insert_id= net_field_length_ll(&pos);
4080  DBUG_PRINT("info",("affected_rows: %lu insert_id: %lu",
4081  (ulong) mysql->affected_rows,
4082  (ulong) mysql->insert_id));
4083  if (protocol_41(mysql))
4084  {
4085  mysql->server_status=uint2korr(pos); pos+=2;
4086  mysql->warning_count=uint2korr(pos); pos+=2;
4087  }
4088  else if (mysql->server_capabilities & CLIENT_TRANSACTIONS)
4089  {
4090  /* MySQL 4.0 protocol */
4091  mysql->server_status=uint2korr(pos); pos+=2;
4092  mysql->warning_count= 0;
4093  }
4094  DBUG_PRINT("info",("status: %u warning_count: %u",
4095  mysql->server_status, mysql->warning_count));
4096  if (pos < mysql->net.read_pos+length && net_field_length(&pos))
4097  mysql->info=(char*) pos;
4098  DBUG_RETURN(0);
4099  }
4100 #ifdef MYSQL_CLIENT
4101  if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
4102  {
4103  int error;
4104 
4105  if (!(mysql->options.client_flag & CLIENT_LOCAL_FILES))
4106  {
4107  set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
4108  DBUG_RETURN(1);
4109  }
4110 
4111  error= handle_local_infile(mysql,(char*) pos);
4112  if ((length= cli_safe_read(mysql)) == packet_error || error)
4113  DBUG_RETURN(1);
4114  goto get_info; /* Get info packet */
4115  }
4116 #endif
4117  if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
4118  mysql->server_status|= SERVER_STATUS_IN_TRANS;
4119 
4120  if (!(fields=cli_read_rows(mysql,(MYSQL_FIELD*)0, protocol_41(mysql) ? 7:5)))
4121  DBUG_RETURN(1);
4122  if (!(mysql->fields=unpack_fields(mysql, fields,&mysql->field_alloc,
4123  (uint) field_count,0,
4124  mysql->server_capabilities)))
4125  DBUG_RETURN(1);
4126  mysql->status= MYSQL_STATUS_GET_RESULT;
4127  mysql->field_count= (uint) field_count;
4128  DBUG_PRINT("exit",("ok"));
4129  DBUG_RETURN(0);
4130 }
4131 
4132 
4133 /*
4134  Send the query and return so we can do something else.
4135  Needs to be followed by mysql_read_query_result() when we want to
4136  finish processing it.
4137 */
4138 
4139 int STDCALL
4140 mysql_send_query(MYSQL* mysql, const char* query, ulong length)
4141 {
4142  DBUG_ENTER("mysql_send_query");
4143  DBUG_RETURN(simple_command(mysql, COM_QUERY, (uchar*) query, length, 1));
4144 }
4145 
4146 
4147 int STDCALL
4148 mysql_real_query(MYSQL *mysql, const char *query, ulong length)
4149 {
4150  int retval;
4151  DBUG_ENTER("mysql_real_query");
4152  DBUG_PRINT("enter",("handle: %p", mysql));
4153  DBUG_PRINT("query",("Query = '%-.*s'", (int) length, query));
4154 
4155  if (mysql_send_query(mysql,query,length))
4156  DBUG_RETURN(1);
4157  retval= (int) (*mysql->methods->read_query_result)(mysql);
4158  DBUG_RETURN(retval);
4159 }
4160 
4161 
4162 /**************************************************************************
4163  Alloc result struct for buffered results. All rows are read to buffer.
4164  mysql_data_seek may be used.
4165 **************************************************************************/
4166 
4167 MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql)
4168 {
4169  MYSQL_RES *result;
4170  DBUG_ENTER("mysql_store_result");
4171 
4172  if (!mysql->fields)
4173  DBUG_RETURN(0);
4174  if (mysql->status != MYSQL_STATUS_GET_RESULT)
4175  {
4176  set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
4177  DBUG_RETURN(0);
4178  }
4179  mysql->status=MYSQL_STATUS_READY; /* server is ready */
4180  if (!(result=(MYSQL_RES*) my_malloc((uint) (sizeof(MYSQL_RES)+
4181  sizeof(ulong) *
4182  mysql->field_count),
4183  MYF(MY_WME | MY_ZEROFILL))))
4184  {
4185  set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
4186  DBUG_RETURN(0);
4187  }
4188  result->methods= mysql->methods;
4189  result->eof=1; /* Marker for buffered */
4190  result->lengths=(ulong*) (result+1);
4191  if (!(result->data=
4192  (*mysql->methods->read_rows)(mysql,mysql->fields,mysql->field_count)))
4193  {
4194  my_free(result);
4195  DBUG_RETURN(0);
4196  }
4197  mysql->affected_rows= result->row_count= result->data->rows;
4198  result->data_cursor= result->data->data;
4199  result->fields= mysql->fields;
4200  result->field_alloc= mysql->field_alloc;
4201  result->field_count= mysql->field_count;
4202  /* The rest of result members is zerofilled in my_malloc */
4203  mysql->fields=0; /* fields is now in result */
4204  clear_alloc_root(&mysql->field_alloc);
4205  /* just in case this was mistakenly called after mysql_stmt_execute() */
4206  mysql->unbuffered_fetch_owner= 0;
4207  DBUG_RETURN(result); /* Data fetched */
4208 }
4209 
4210 
4211 /**************************************************************************
4212  Alloc struct for use with unbuffered reads. Data is fetched by domand
4213  when calling to mysql_fetch_row.
4214  mysql_data_seek is a noop.
4215 
4216  No other queries may be specified with the same MYSQL handle.
4217  There shouldn't be much processing per row because mysql server shouldn't
4218  have to wait for the client (and will not wait more than 30 sec/packet).
4219 **************************************************************************/
4220 
4221 static MYSQL_RES * cli_use_result(MYSQL *mysql)
4222 {
4223  MYSQL_RES *result;
4224  DBUG_ENTER("cli_use_result");
4225 
4226  if (!mysql->fields)
4227  DBUG_RETURN(0);
4228  if (mysql->status != MYSQL_STATUS_GET_RESULT)
4229  {
4230  set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
4231  DBUG_RETURN(0);
4232  }
4233  if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result)+
4234  sizeof(ulong)*mysql->field_count,
4235  MYF(MY_WME | MY_ZEROFILL))))
4236  DBUG_RETURN(0);
4237  result->lengths=(ulong*) (result+1);
4238  result->methods= mysql->methods;
4239  if (!(result->row=(MYSQL_ROW)
4240  my_malloc(sizeof(result->row[0])*(mysql->field_count+1), MYF(MY_WME))))
4241  { /* Ptrs: to one row */
4242  my_free(result);
4243  DBUG_RETURN(0);
4244  }
4245  result->fields= mysql->fields;
4246  result->field_alloc= mysql->field_alloc;
4247  result->field_count= mysql->field_count;
4248  result->current_field=0;
4249  result->handle= mysql;
4250  result->current_row= 0;
4251  mysql->fields=0; /* fields is now in result */
4252  clear_alloc_root(&mysql->field_alloc);
4253  mysql->status=MYSQL_STATUS_USE_RESULT;
4254  mysql->unbuffered_fetch_owner= &result->unbuffered_fetch_cancelled;
4255  DBUG_RETURN(result); /* Data is read to be fetched */
4256 }
4257 
4258 
4259 /**************************************************************************
4260  Return next row of the query results
4261 **************************************************************************/
4262 
4263 MYSQL_ROW STDCALL
4264 mysql_fetch_row(MYSQL_RES *res)
4265 {
4266  DBUG_ENTER("mysql_fetch_row");
4267  if (!res->data)
4268  { /* Unbufferred fetch */
4269  if (!res->eof)
4270  {
4271  MYSQL *mysql= res->handle;
4272  if (mysql->status != MYSQL_STATUS_USE_RESULT)
4273  {
4274  set_mysql_error(mysql,
4275  res->unbuffered_fetch_cancelled ?
4276  CR_FETCH_CANCELED : CR_COMMANDS_OUT_OF_SYNC,
4277  unknown_sqlstate);
4278  }
4279  else if (!(read_one_row(mysql, res->field_count, res->row, res->lengths)))
4280  {
4281  res->row_count++;
4282  DBUG_RETURN(res->current_row=res->row);
4283  }
4284  DBUG_PRINT("info",("end of data"));
4285  res->eof=1;
4286  mysql->status=MYSQL_STATUS_READY;
4287  /*
4288  Reset only if owner points to us: there is a chance that somebody
4289  started new query after mysql_stmt_close():
4290  */
4291  if (mysql->unbuffered_fetch_owner == &res->unbuffered_fetch_cancelled)
4292  mysql->unbuffered_fetch_owner= 0;
4293  /* Don't clear handle in mysql_free_result */
4294  res->handle=0;
4295  }
4296  DBUG_RETURN((MYSQL_ROW) NULL);
4297  }
4298  {
4299  MYSQL_ROW tmp;
4300  if (!res->data_cursor)
4301  {
4302  DBUG_PRINT("info",("end of data"));
4303  DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL);
4304  }
4305  tmp = res->data_cursor->data;
4306  res->data_cursor = res->data_cursor->next;
4307  DBUG_RETURN(res->current_row=tmp);
4308  }
4309 }
4310 
4311 
4312 /**************************************************************************
4313  Get column lengths of the current row
4314  If one uses mysql_use_result, res->lengths contains the length information,
4315  else the lengths are calculated from the offset between pointers.
4316 **************************************************************************/
4317 
4318 ulong * STDCALL
4319 mysql_fetch_lengths(MYSQL_RES *res)
4320 {
4321  MYSQL_ROW column;
4322 
4323  if (!(column=res->current_row))
4324  return 0; /* Something is wrong */
4325  if (res->data)
4326  (*res->methods->fetch_lengths)(res->lengths, column, res->field_count);
4327  return res->lengths;
4328 }
4329 
4330 int STDCALL
4331 mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg)
4332 {
4333  DBUG_ENTER("mysql_option");
4334  DBUG_PRINT("enter",("option: %d",(int) option));
4335  switch (option) {
4336  case MYSQL_OPT_CONNECT_TIMEOUT:
4337  mysql->options.connect_timeout= *(uint*) arg;
4338  break;
4339  case MYSQL_OPT_READ_TIMEOUT:
4340  mysql->options.read_timeout= *(uint*) arg;
4341  break;
4342  case MYSQL_OPT_WRITE_TIMEOUT:
4343  mysql->options.write_timeout= *(uint*) arg;
4344  break;
4345  case MYSQL_OPT_COMPRESS:
4346  mysql->options.compress= 1; /* Remember for connect */
4347  mysql->options.client_flag|= CLIENT_COMPRESS;
4348  break;
4349  case MYSQL_OPT_NAMED_PIPE: /* This option is depricated */
4350  mysql->options.protocol=MYSQL_PROTOCOL_PIPE; /* Force named pipe */
4351  break;
4352  case MYSQL_OPT_LOCAL_INFILE: /* Allow LOAD DATA LOCAL ?*/
4353  if (!arg || test(*(uint*) arg))
4354  mysql->options.client_flag|= CLIENT_LOCAL_FILES;
4355  else
4356  mysql->options.client_flag&= ~CLIENT_LOCAL_FILES;
4357  break;
4358  case MYSQL_INIT_COMMAND:
4359  add_init_command(&mysql->options,arg);
4360  break;
4361  case MYSQL_READ_DEFAULT_FILE:
4362  my_free(mysql->options.my_cnf_file);
4363  mysql->options.my_cnf_file=my_strdup(arg,MYF(MY_WME));
4364  break;
4365  case MYSQL_READ_DEFAULT_GROUP:
4366  my_free(mysql->options.my_cnf_group);
4367  mysql->options.my_cnf_group=my_strdup(arg,MYF(MY_WME));
4368  break;
4369  case MYSQL_SET_CHARSET_DIR:
4370  my_free(mysql->options.charset_dir);
4371  mysql->options.charset_dir=my_strdup(arg,MYF(MY_WME));
4372  break;
4373  case MYSQL_SET_CHARSET_NAME:
4374  my_free(mysql->options.charset_name);
4375  mysql->options.charset_name=my_strdup(arg,MYF(MY_WME));
4376  break;
4377  case MYSQL_OPT_PROTOCOL:
4378  mysql->options.protocol= *(uint*) arg;
4379  break;
4380  case MYSQL_SHARED_MEMORY_BASE_NAME:
4381 #ifdef HAVE_SMEM
4382  if (mysql->options.shared_memory_base_name != def_shared_memory_base_name)
4383  my_free(mysql->options.shared_memory_base_name);
4384  mysql->options.shared_memory_base_name=my_strdup(arg,MYF(MY_WME));
4385 #endif
4386  break;
4387  case MYSQL_OPT_USE_REMOTE_CONNECTION:
4388  case MYSQL_OPT_USE_EMBEDDED_CONNECTION:
4389  case MYSQL_OPT_GUESS_CONNECTION:
4390  mysql->options.methods_to_use= option;
4391  break;
4392  case MYSQL_SET_CLIENT_IP:
4393  mysql->options.ci.client_ip= my_strdup(arg, MYF(MY_WME));
4394  break;
4395  case MYSQL_SECURE_AUTH:
4396  mysql->options.secure_auth= *(my_bool *) arg;
4397  break;
4398  case MYSQL_REPORT_DATA_TRUNCATION:
4399  mysql->options.report_data_truncation= test(*(my_bool *) arg);
4400  break;
4401  case MYSQL_OPT_RECONNECT:
4402  mysql->reconnect= *(my_bool *) arg;
4403  break;
4404  case MYSQL_OPT_BIND:
4405  my_free(mysql->options.ci.bind_address);
4406  mysql->options.ci.bind_address= my_strdup(arg, MYF(MY_WME));
4407  break;
4408  case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
4409  if (*(my_bool*) arg)
4410  mysql->options.client_flag|= CLIENT_SSL_VERIFY_SERVER_CERT;
4411  else
4412  mysql->options.client_flag&= ~CLIENT_SSL_VERIFY_SERVER_CERT;
4413  break;
4414  case MYSQL_PLUGIN_DIR:
4415  EXTENSION_SET_STRING(&mysql->options, plugin_dir, arg);
4416  break;
4417  case MYSQL_DEFAULT_AUTH:
4418  EXTENSION_SET_STRING(&mysql->options, default_auth, arg);
4419  break;
4420  case MYSQL_OPT_SSL_KEY: SET_SSL_OPTION(ssl_key, arg); break;
4421  case MYSQL_OPT_SSL_CERT: SET_SSL_OPTION(ssl_cert, arg); break;
4422  case MYSQL_OPT_SSL_CA: SET_SSL_OPTION(ssl_ca, arg); break;
4423  case MYSQL_OPT_SSL_CAPATH: SET_SSL_OPTION(ssl_capath, arg); break;
4424  case MYSQL_OPT_SSL_CIPHER: SET_SSL_OPTION(ssl_cipher, arg); break;
4425  case MYSQL_OPT_SSL_CRL: EXTENSION_SET_SSL_STRING(&mysql->options,
4426  ssl_crl, arg);
4427  break;
4428  case MYSQL_OPT_SSL_CRLPATH: EXTENSION_SET_SSL_STRING(&mysql->options,
4429  ssl_crlpath, arg);
4430  break;
4431  case MYSQL_SERVER_PUBLIC_KEY:
4432  EXTENSION_SET_STRING(&mysql->options, server_public_key_path, arg);
4433  break;
4434 
4435  case MYSQL_OPT_CONNECT_ATTR_RESET:
4436  ENSURE_EXTENSIONS_PRESENT(&mysql->options);
4437  if (my_hash_inited(&mysql->options.extension->connection_attributes))
4438  {
4439  my_hash_free(&mysql->options.extension->connection_attributes);
4440  mysql->options.extension->connection_attributes_length= 0;
4441  }
4442  break;
4443  case MYSQL_OPT_CONNECT_ATTR_DELETE:
4444  ENSURE_EXTENSIONS_PRESENT(&mysql->options);
4445  if (my_hash_inited(&mysql->options.extension->connection_attributes))
4446  {
4447  size_t len;
4448  uchar *elt;
4449 
4450  len= arg ? strlen(arg) : 0;
4451 
4452  if (len)
4453  {
4454  elt= my_hash_search(&mysql->options.extension->connection_attributes,
4455  arg, len);
4456  if (elt)
4457  {
4458  LEX_STRING *attr= (LEX_STRING *) elt;
4459  LEX_STRING *key= attr, *value= attr + 1;
4460 
4461  mysql->options.extension->connection_attributes_length-=
4462  get_length_store_length(key->length) + key->length +
4463  get_length_store_length(value->length) + value->length;
4464 
4465  my_hash_delete(&mysql->options.extension->connection_attributes,
4466  elt);
4467 
4468  }
4469  }
4470  }
4471  break;
4472  case MYSQL_ENABLE_CLEARTEXT_PLUGIN:
4473  ENSURE_EXTENSIONS_PRESENT(&mysql->options);
4474  mysql->options.extension->enable_cleartext_plugin=
4475  (*(my_bool*) arg) ? TRUE : FALSE;
4476  break;
4477  case MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS:
4478  if (*(my_bool*) arg)
4479  mysql->options.client_flag|= CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS;
4480  else
4481  mysql->options.client_flag&= ~CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS;
4482  break;
4483 
4484  default:
4485  DBUG_RETURN(1);
4486  }
4487  DBUG_RETURN(0);
4488 }
4489 
4490 
4494 uchar *
4495 get_attr_key(LEX_STRING *part, size_t *length,
4496  my_bool not_used __attribute__((unused)))
4497 {
4498  *length= part[0].length;
4499  return (uchar *) part[0].str;
4500 }
4501 
4502 int STDCALL
4503 mysql_options4(MYSQL *mysql,enum mysql_option option,
4504  const void *arg1, const void *arg2)
4505 {
4506  DBUG_ENTER("mysql_option");
4507  DBUG_PRINT("enter",("option: %d",(int) option));
4508 
4509  switch (option)
4510  {
4511  case MYSQL_OPT_CONNECT_ATTR_ADD:
4512  {
4513  LEX_STRING *elt;
4514  char *key, *value;
4515  size_t key_len= arg1 ? strlen(arg1) : 0,
4516  value_len= arg2 ? strlen(arg2) : 0;
4517  size_t attr_storage_length= key_len + value_len;
4518 
4519  /* we can't have a zero length key */
4520  if (!key_len)
4521  {
4522  set_mysql_error(mysql, CR_INVALID_PARAMETER_NO, unknown_sqlstate);
4523  DBUG_RETURN(1);
4524  }
4525 
4526  /* calculate the total storage length of the attribute */
4527  attr_storage_length+= get_length_store_length(key_len);
4528  attr_storage_length+= get_length_store_length(value_len);
4529 
4530  ENSURE_EXTENSIONS_PRESENT(&mysql->options);
4531 
4532  /*
4533  Throw and error if the maximum combined length of the attribute value
4534  will be greater than the maximum that we can safely transmit.
4535  */
4536  if (attr_storage_length +
4537  mysql->options.extension->connection_attributes_length >
4538  MAX_CONNECTION_ATTR_STORAGE_LENGTH)
4539  {
4540  set_mysql_error(mysql, CR_INVALID_PARAMETER_NO, unknown_sqlstate);
4541  DBUG_RETURN(1);
4542  }
4543 
4544  if (!my_hash_inited(&mysql->options.extension->connection_attributes))
4545  {
4546  if (my_hash_init(&mysql->options.extension->connection_attributes,
4547  &my_charset_bin, 0, 0, 0, (my_hash_get_key) get_attr_key,
4548  my_free, HASH_UNIQUE))
4549  {
4550  set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
4551  DBUG_RETURN(1);
4552  }
4553  }
4554  if (!my_multi_malloc(MY_WME,
4555  &elt, 2 * sizeof(LEX_STRING),
4556  &key, key_len + 1,
4557  &value, value_len + 1,
4558  NULL))
4559  {
4560  set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
4561  DBUG_RETURN(1);
4562  }
4563  elt[0].str= key; elt[0].length= key_len;
4564  elt[1].str= value; elt[1].length= value_len;
4565  if (key_len)
4566  memcpy(key, arg1, key_len);
4567  key[key_len]= 0;
4568  if (value_len)
4569  memcpy(value, arg2, value_len);
4570  value[value_len]= 0;
4571  if (my_hash_insert(&mysql->options.extension->connection_attributes,
4572  (uchar *) elt))
4573  {
4574  /* can't insert the value */
4575  my_free(elt);
4576  set_mysql_error(mysql, CR_DUPLICATE_CONNECTION_ATTR,
4577  unknown_sqlstate);
4578  DBUG_RETURN(1);
4579  }
4580 
4581  mysql->options.extension->connection_attributes_length+=
4582  attr_storage_length;
4583 
4584  break;
4585  }
4586 
4587  default:
4588  DBUG_RETURN(1);
4589  }
4590  DBUG_RETURN(0);
4591 }
4592 
4593 
4594 /****************************************************************************
4595  Functions to get information from the MySQL structure
4596  These are functions to make shared libraries more usable.
4597 ****************************************************************************/
4598 
4599 /* MYSQL_RES */
4600 my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res)
4601 {
4602  return res->row_count;
4603 }
4604 
4605 unsigned int STDCALL mysql_num_fields(MYSQL_RES *res)
4606 {
4607  return res->field_count;
4608 }
4609 
4610 uint STDCALL mysql_errno(MYSQL *mysql)
4611 {
4612  return mysql ? mysql->net.last_errno : mysql_server_last_errno;
4613 }
4614 
4615 
4616 const char * STDCALL mysql_error(MYSQL *mysql)
4617 {
4618  return mysql ? mysql->net.last_error : mysql_server_last_error;
4619 }
4620 
4621 
4622 /*
4623  Get version number for server in a form easy to test on
4624 
4625  SYNOPSIS
4626  mysql_get_server_version()
4627  mysql Connection
4628 
4629  EXAMPLE
4630  4.1.0-alfa -> 40100
4631 
4632  NOTES
4633  We will ensure that a newer server always has a bigger number.
4634 
4635  RETURN
4636  Signed number > 323000
4637 */
4638 
4639 ulong STDCALL
4640 mysql_get_server_version(MYSQL *mysql)
4641 {
4642  uint major, minor, version;
4643  char *pos= mysql->server_version, *end_pos;
4644  major= (uint) strtoul(pos, &end_pos, 10); pos=end_pos+1;
4645  minor= (uint) strtoul(pos, &end_pos, 10); pos=end_pos+1;
4646  version= (uint) strtoul(pos, &end_pos, 10);
4647  return (ulong) major*10000L+(ulong) (minor*100+version);
4648 }
4649 
4650 
4651 /*
4652  mysql_set_character_set function sends SET NAMES cs_name to
4653  the server (which changes character_set_client, character_set_result
4654  and character_set_connection) and updates mysql->charset so other
4655  functions like mysql_real_escape will work correctly.
4656 */
4657 int STDCALL mysql_set_character_set(MYSQL *mysql, const char *cs_name)
4658 {
4659  struct charset_info_st *cs;
4660  const char *save_csdir= charsets_dir;
4661 
4662  if (mysql->options.charset_dir)
4663  charsets_dir= mysql->options.charset_dir;
4664 
4665  if (!mysql->net.vio)
4666  {
4667  /* Initialize with automatic OS character set detection. */
4668  mysql_options(mysql, MYSQL_SET_CHARSET_NAME, cs_name);
4669  mysql_init_character_set(mysql);
4670  /*
4671  In case of automatic OS character set detection
4672  mysql_init_character_set changes mysql->options.charset_name
4673  from "auto" to the real character set name.
4674  Reset cs_name to the detected character set name, accordingly.
4675  */
4676  cs_name= mysql->options.charset_name;
4677  }
4678 
4679  if (strlen(cs_name) < MY_CS_NAME_SIZE &&
4680  (cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0))))
4681  {
4682  char buff[MY_CS_NAME_SIZE + 10];
4683  charsets_dir= save_csdir;
4684  if (!mysql->net.vio)
4685  {
4686  /* If there is no connection yet we don't send "SET NAMES" query */
4687  mysql->charset= cs;
4688  return 0;
4689  }
4690  /* Skip execution of "SET NAMES" for pre-4.1 servers */
4691  if (mysql_get_server_version(mysql) < 40100)
4692  return 0;
4693  sprintf(buff, "SET NAMES %s", cs_name);
4694  if (!mysql_real_query(mysql, buff, (uint) strlen(buff)))
4695  {
4696  mysql->charset= cs;
4697  }
4698  }
4699  else
4700  {
4701  char cs_dir_name[FN_REFLEN];
4702  get_charsets_dir(cs_dir_name);
4703  set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate,
4704  ER(CR_CANT_READ_CHARSET), cs_name, cs_dir_name);
4705  }
4706  charsets_dir= save_csdir;
4707  return mysql->net.last_errno;
4708 }
4709 
4714 static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
4715 {
4716  int pkt_len;
4717  uchar *pkt;
4718 
4719  DBUG_ENTER("native_password_auth_client");
4720 
4721 
4722  if (((MCPVIO_EXT *)vio)->mysql_change_user)
4723  {
4724  /*
4725  in mysql_change_user() the client sends the first packet.
4726  we use the old scramble.
4727  */
4728  pkt= (uchar*)mysql->scramble;
4729  pkt_len= SCRAMBLE_LENGTH + 1;
4730  }
4731  else
4732  {
4733  /* read the scramble */
4734  if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
4735  DBUG_RETURN(CR_ERROR);
4736 
4737  if (pkt_len != SCRAMBLE_LENGTH + 1)
4738  DBUG_RETURN(CR_SERVER_HANDSHAKE_ERR);
4739 
4740  /* save it in MYSQL */
4741  memcpy(mysql->scramble, pkt, SCRAMBLE_LENGTH);
4742  mysql->scramble[SCRAMBLE_LENGTH] = 0;
4743  }
4744 
4745  if (mysql->passwd[0])
4746  {
4747  char scrambled[SCRAMBLE_LENGTH + 1];
4748  DBUG_PRINT("info", ("sending scramble"));
4749  scramble(scrambled, (char*)pkt, mysql->passwd);
4750  if (vio->write_packet(vio, (uchar*)scrambled, SCRAMBLE_LENGTH))
4751  DBUG_RETURN(CR_ERROR);
4752  }
4753  else
4754  {
4755  DBUG_PRINT("info", ("no password"));
4756  if (vio->write_packet(vio, 0, 0)) /* no password */
4757  DBUG_RETURN(CR_ERROR);
4758  }
4759 
4760  DBUG_RETURN(CR_OK);
4761 }
4762 
4767 static int old_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
4768 {
4769  uchar *pkt;
4770  int pkt_len;
4771 
4772  DBUG_ENTER("old_password_auth_client");
4773 
4774  if (((MCPVIO_EXT *)vio)->mysql_change_user)
4775  {
4776  /*
4777  in mysql_change_user() the client sends the first packet.
4778  we use the old scramble.
4779  */
4780  pkt= (uchar*)mysql->scramble;
4781  pkt_len= SCRAMBLE_LENGTH_323 + 1;
4782  }
4783  else
4784  {
4785  /* read the scramble */
4786  if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
4787  DBUG_RETURN(CR_ERROR);
4788 
4789  if (pkt_len != SCRAMBLE_LENGTH_323 + 1 &&
4790  pkt_len != SCRAMBLE_LENGTH + 1)
4791  DBUG_RETURN(CR_SERVER_HANDSHAKE_ERR);
4792 
4793  /*
4794  save it in MYSQL.
4795  Copy data of length SCRAMBLE_LENGTH_323 or SCRAMBLE_LENGTH
4796  to ensure that buffer overflow does not occur.
4797  */
4798  memcpy(mysql->scramble, pkt, (pkt_len - 1));
4799  mysql->scramble[pkt_len-1] = 0;
4800  }
4801 
4802  if (mysql->passwd[0])
4803  {
4804  /*
4805  If --secure-auth option is used, throw an error.
4806  Note that, we do not need to check for CLIENT_SECURE_CONNECTION
4807  capability of server. If server is not capable of handling secure
4808  connections, we would have raised error before reaching here.
4809 
4810  TODO: Change following code to access MYSQL structure through
4811  client-side plugin service.
4812  */
4813  if (mysql->options.secure_auth)
4814  {
4815  set_mysql_error(mysql, CR_SECURE_AUTH, unknown_sqlstate);
4816  DBUG_RETURN(CR_ERROR);
4817  }
4818  else
4819  {
4820  char scrambled[SCRAMBLE_LENGTH_323 + 1];
4821  scramble_323(scrambled, (char*)pkt, mysql->passwd);
4822  if (vio->write_packet(vio, (uchar*)scrambled, SCRAMBLE_LENGTH_323 + 1))
4823  DBUG_RETURN(CR_ERROR);
4824  }
4825  }
4826  else
4827  if (vio->write_packet(vio, 0, 0)) /* no password */
4828  DBUG_RETURN(CR_ERROR);
4829 
4830  DBUG_RETURN(CR_OK);
4831 }
4832 
4837 static int clear_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
4838 {
4839  int res;
4840 
4841  /* send password in clear text */
4842  res= vio->write_packet(vio, (const unsigned char *) mysql->passwd,
4843  strlen(mysql->passwd) + 1);
4844 
4845  return res ? CR_ERROR : CR_OK;
4846 }