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