1/************************************************************************************
2 Copyright (C) 2000, 2012 MySQL AB & MySQL Finland AB & TCX DataKonsult AB,
3 Monty Program AB
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not see <http://www.gnu.org/licenses>
17 or write to the Free Software Foundation, Inc.,
18 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
19
20 Part of this code includes code from the PHP project which
21 is freely available from http://www.php.net
22*************************************************************************************/
23
24#include <ma_global.h>
25
26#include <ma_sys.h>
27#include <ma_string.h>
28#include <mariadb_ctype.h>
29#include <ma_common.h>
30#include "ma_context.h"
31#include "mysql.h"
32#include "mariadb_version.h"
33#include "ma_server_error.h"
34#include <mariadb/ma_io.h>
35#include "errmsg.h"
36#include <sys/stat.h>
37#include <signal.h>
38#include <time.h>
39#include <mariadb_dyncol.h>
40
41#ifdef HAVE_PWD_H
42#include <pwd.h>
43#endif
44#if !defined(MSDOS) && !defined(_WIN32)
45#include <sys/socket.h>
46#include <netinet/in.h>
47#include <arpa/inet.h>
48#include <netdb.h>
49#ifdef HAVE_SELECT_H
50# include <select.h>
51#endif
52#ifdef HAVE_SYS_SELECT_H
53#include <sys/select.h>
54#endif
55#endif
56#ifdef HAVE_SYS_UN_H
57# include <sys/un.h>
58#endif
59#ifndef INADDR_NONE
60#define INADDR_NONE -1
61#endif
62#include <ma_sha1.h>
63#ifndef _WIN32
64#include <poll.h>
65#endif
66#include <ma_pvio.h>
67#ifdef HAVE_TLS
68#include <ma_tls.h>
69#endif
70#include <mysql/client_plugin.h>
71#ifdef _WIN32
72#include "Shlwapi.h"
73#define strncasecmp _strnicmp
74#endif
75
76#define ASYNC_CONTEXT_DEFAULT_STACK_SIZE (4096*15)
77#define MA_RPL_VERSION_HACK "5.5.5-"
78
79#undef max_allowed_packet
80#undef net_buffer_length
81extern ulong max_allowed_packet; /* net.c */
82extern ulong net_buffer_length; /* net.c */
83
84static MYSQL_PARAMETERS mariadb_internal_parameters= {&max_allowed_packet, &net_buffer_length, 0};
85static my_bool mysql_client_init=0;
86static void mysql_close_options(MYSQL *mysql);
87extern void release_configuration_dirs();
88extern char **get_default_configuration_dirs();
89extern my_bool ma_init_done;
90extern my_bool mysql_ps_subsystem_initialized;
91extern my_bool mysql_handle_local_infile(MYSQL *mysql, const char *filename, my_bool can_local_infile);
92extern const MARIADB_CHARSET_INFO * mysql_find_charset_nr(uint charsetnr);
93extern const MARIADB_CHARSET_INFO * mysql_find_charset_name(const char * const name);
94extern my_bool set_default_charset_by_name(const char *cs_name, myf flags __attribute__((unused)));
95extern int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
96 const char *data_plugin, const char *db);
97extern int net_add_multi_command(NET *net, uchar command, const uchar *packet,
98 size_t length);
99
100extern LIST *pvio_callback;
101
102/* prepare statement methods from my_stmt.c */
103extern my_bool mthd_supported_buffer_type(enum enum_field_types type);
104extern my_bool mthd_stmt_read_prepare_response(MYSQL_STMT *stmt);
105extern my_bool mthd_stmt_get_param_metadata(MYSQL_STMT *stmt);
106extern my_bool mthd_stmt_get_result_metadata(MYSQL_STMT *stmt);
107extern int mthd_stmt_fetch_row(MYSQL_STMT *stmt, unsigned char **row);
108extern int mthd_stmt_fetch_to_bind(MYSQL_STMT *stmt, unsigned char *row);
109extern int mthd_stmt_read_all_rows(MYSQL_STMT *stmt);
110extern void mthd_stmt_flush_unbuffered(MYSQL_STMT *stmt);
111extern my_bool _mariadb_read_options(MYSQL *mysql, const char *dir, const char *config_file, char *group, unsigned int recursion);
112extern unsigned char *mysql_net_store_length(unsigned char *packet, size_t length);
113
114extern void
115my_context_install_suspend_resume_hook(struct mysql_async_context *b,
116 void (*hook)(my_bool, void *),
117 void *user_data);
118
119uint mysql_port=0;
120my_string mysql_unix_port=0;
121
122#define CONNECT_TIMEOUT 0
123
124struct st_mariadb_methods MARIADB_DEFAULT_METHODS;
125
126#if defined(MSDOS) || defined(_WIN32)
127// socket_errno is defined in ma_global.h for all platforms
128#define perror(A)
129#else
130#include <errno.h>
131#define SOCKET_ERROR -1
132#endif /* _WIN32 */
133
134#include <mysql/client_plugin.h>
135
136#define IS_CONNHDLR_ACTIVE(mysql)\
137 ((mysql)->extension && (mysql)->extension->conn_hdlr)
138
139static void end_server(MYSQL *mysql);
140static void mysql_close_memory(MYSQL *mysql);
141void read_user_name(char *name);
142my_bool STDCALL mariadb_reconnect(MYSQL *mysql);
143static int cli_report_progress(MYSQL *mysql, uchar *packet, uint length);
144
145extern int mysql_client_plugin_init();
146extern void mysql_client_plugin_deinit();
147
148/* net_get_error */
149void net_get_error(char *buf, size_t buf_len,
150 char *error, size_t error_len,
151 unsigned int *error_no,
152 char *sqlstate)
153{
154 char *p= buf;
155 size_t error_msg_len= 0;
156
157 if (buf_len > 2)
158 {
159 *error_no= uint2korr(p);
160 p+= 2;
161
162 /* since 4.1 sqlstate is following */
163 if (*p == '#')
164 {
165 memcpy(sqlstate, ++p, SQLSTATE_LENGTH);
166 p+= SQLSTATE_LENGTH;
167 }
168 error_msg_len= buf_len - (p - buf);
169 error_msg_len= MIN(error_msg_len, error_len - 1);
170 memcpy(error, p, error_msg_len);
171 }
172 else
173 {
174 *error_no= CR_UNKNOWN_ERROR;
175 memcpy(sqlstate, SQLSTATE_UNKNOWN, SQLSTATE_LENGTH);
176 }
177}
178
179/*****************************************************************************
180** read a packet from server. Give error message if socket was down
181** or packet is an error message
182*****************************************************************************/
183
184ulong
185ma_net_safe_read(MYSQL *mysql)
186{
187 NET *net= &mysql->net;
188 ulong len=0;
189
190restart:
191 if (net->pvio != 0)
192 len=ma_net_read(net);
193
194 if (len == packet_error || len == 0)
195 {
196 end_server(mysql);
197 my_set_error(mysql, net->last_errno == ER_NET_PACKET_TOO_LARGE ?
198 CR_NET_PACKET_TOO_LARGE:
199 CR_SERVER_LOST,
200 SQLSTATE_UNKNOWN, 0, errno);
201 return(packet_error);
202 }
203 if (net->read_pos[0] == 255)
204 {
205 if (len > 3)
206 {
207 char *pos=(char*) net->read_pos+1;
208 uint last_errno=uint2korr(pos);
209 pos+=2;
210 len-=2;
211
212 if (last_errno== 65535 &&
213 ((mariadb_connection(mysql) && (mysql->server_capabilities & CLIENT_PROGRESS)) ||
214 (!(mysql->extension->mariadb_server_capabilities & MARIADB_CLIENT_PROGRESS << 32))))
215 {
216 if (cli_report_progress(mysql, (uchar *)pos, (uint) (len-1)))
217 {
218 /* Wrong packet */
219 my_set_error(mysql, CR_MALFORMED_PACKET, SQLSTATE_UNKNOWN, 0);
220 return (packet_error);
221 }
222 goto restart;
223 }
224 net->last_errno= last_errno;
225 if (pos[0]== '#')
226 {
227 ma_strmake(net->sqlstate, pos+1, SQLSTATE_LENGTH);
228 pos+= SQLSTATE_LENGTH + 1;
229 }
230 else
231 {
232 strncpy(net->sqlstate, SQLSTATE_UNKNOWN, SQLSTATE_LENGTH);
233 }
234 ma_strmake(net->last_error,(char*) pos,
235 min(len,sizeof(net->last_error)-1));
236 }
237 else
238 {
239 my_set_error(mysql, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, 0);
240 }
241
242 mysql->server_status&= ~SERVER_MORE_RESULTS_EXIST;
243
244 return(packet_error);
245 }
246 return len;
247}
248
249/*
250 Report progress to the client
251
252 RETURN VALUES
253 0 ok
254 1 error
255*/
256static int cli_report_progress(MYSQL *mysql, uchar *packet, uint length)
257{
258 uint stage, max_stage, proc_length;
259 double progress;
260 uchar *start= packet;
261
262 if (length < 5)
263 return 1; /* Wrong packet */
264
265 if (!(mysql->options.extension && mysql->options.extension->report_progress))
266 return 0; /* No callback, ignore packet */
267
268 packet++; /* Ignore number of strings */
269 stage= (uint) *packet++;
270 max_stage= (uint) *packet++;
271 progress= uint3korr(packet)/1000.0;
272 packet+= 3;
273 proc_length= net_field_length(&packet);
274 if (packet + proc_length > start + length)
275 return 1; /* Wrong packet */
276 (*mysql->options.extension->report_progress)(mysql, stage, max_stage,
277 progress, (char*) packet,
278 proc_length);
279 return 0;
280}
281
282/* Get the length of next field. Change parameter to point at fieldstart */
283ulong
284net_field_length(uchar **packet)
285{
286 reg1 uchar *pos= *packet;
287 if (*pos < 251)
288 {
289 (*packet)++;
290 return (ulong) *pos;
291 }
292 if (*pos == 251)
293 {
294 (*packet)++;
295 return NULL_LENGTH;
296 }
297 if (*pos == 252)
298 {
299 (*packet)+=3;
300 return (ulong) uint2korr(pos+1);
301 }
302 if (*pos == 253)
303 {
304 (*packet)+=4;
305 return (ulong) uint3korr(pos+1);
306 }
307 (*packet)+=9; /* Must be 254 when here */
308 return (ulong) uint4korr(pos+1);
309}
310
311/* Same as above, but returns ulonglong values */
312
313static unsigned long long
314net_field_length_ll(uchar **packet)
315{
316 reg1 uchar *pos= *packet;
317 if (*pos < 251)
318 {
319 (*packet)++;
320 return (unsigned long long) *pos;
321 }
322 if (*pos == 251)
323 {
324 (*packet)++;
325 return (unsigned long long) NULL_LENGTH;
326 }
327 if (*pos == 252)
328 {
329 (*packet)+=3;
330 return (unsigned long long) uint2korr(pos+1);
331 }
332 if (*pos == 253)
333 {
334 (*packet)+=4;
335 return (unsigned long long) uint3korr(pos+1);
336 }
337 (*packet)+=9; /* Must be 254 when here */
338#ifdef NO_CLIENT_LONGLONG
339 return (unsigned long long) uint4korr(pos+1);
340#else
341 return (unsigned long long) uint8korr(pos+1);
342#endif
343}
344
345
346void free_rows(MYSQL_DATA *cur)
347{
348 if (cur)
349 {
350 ma_free_root(&cur->alloc,MYF(0));
351 free(cur);
352 }
353}
354
355int
356mthd_my_send_cmd(MYSQL *mysql,enum enum_server_command command, const char *arg,
357 size_t length, my_bool skipp_check, void *opt_arg)
358{
359 NET *net= &mysql->net;
360 int result= -1;
361 if (mysql->net.pvio == 0)
362 {
363 /* Do reconnect if possible */
364 if (mariadb_reconnect(mysql))
365 return(1);
366 }
367 if (mysql->status != MYSQL_STATUS_READY ||
368 mysql->server_status & SERVER_MORE_RESULTS_EXIST)
369 {
370 SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
371 goto end;
372 }
373
374 if (IS_CONNHDLR_ACTIVE(mysql))
375 {
376 result= mysql->extension->conn_hdlr->plugin->set_connection(mysql, command, arg, length, skipp_check, opt_arg);
377 if (result== -1)
378 return(result);
379 }
380
381 CLEAR_CLIENT_ERROR(mysql);
382
383 mysql->info=0;
384 mysql->affected_rows= ~(unsigned long long) 0;
385 ma_net_clear(net); /* Clear receive buffer */
386 if (!arg)
387 arg="";
388
389 if (net->extension->multi_status== COM_MULTI_ENABLED)
390 {
391 return net_add_multi_command(net, command, (const uchar *)arg, length);
392 }
393
394 if (ma_net_write_command(net,(uchar) command,arg,
395 length ? length : (ulong) strlen(arg), 0))
396 {
397 if (net->last_errno == ER_NET_PACKET_TOO_LARGE)
398 {
399 my_set_error(mysql, CR_NET_PACKET_TOO_LARGE, SQLSTATE_UNKNOWN, 0);
400 goto end;
401 }
402 end_server(mysql);
403 if (mariadb_reconnect(mysql))
404 goto end;
405 if (ma_net_write_command(net,(uchar) command,arg,
406 length ? length : (ulong) strlen(arg), 0))
407 {
408 my_set_error(mysql, CR_SERVER_GONE_ERROR, SQLSTATE_UNKNOWN, 0);
409 goto end;
410 }
411 }
412 result=0;
413
414 if (net->extension->multi_status > COM_MULTI_OFF)
415 skipp_check= 1;
416
417 if (!skipp_check)
418 {
419 result= ((mysql->packet_length=ma_net_safe_read(mysql)) == packet_error ?
420 1 : 0);
421 }
422 end:
423 return(result);
424}
425
426int
427ma_simple_command(MYSQL *mysql,enum enum_server_command command, const char *arg,
428 size_t length, my_bool skipp_check, void *opt_arg)
429{
430 if ((mysql->options.client_flag & CLIENT_LOCAL_FILES) &&
431 mysql->options.extension && mysql->extension->auto_local_infile == WAIT_FOR_QUERY &&
432 arg && (*arg == 'l' || *arg == 'L') &&
433 command == COM_QUERY)
434 {
435 if (strncasecmp(arg, "load", 4) == 0)
436 mysql->extension->auto_local_infile= ACCEPT_FILE_REQUEST;
437 }
438 return mysql->methods->db_command(mysql, command, arg, length, skipp_check, opt_arg);
439}
440
441int ma_multi_command(MYSQL *mysql, enum enum_multi_status status)
442{
443 NET *net= &mysql->net;
444
445 switch (status) {
446 case COM_MULTI_OFF:
447 ma_net_clear(net);
448 net->extension->multi_status= status;
449 return 0;
450 case COM_MULTI_ENABLED:
451 if (net->extension->multi_status > COM_MULTI_DISABLED)
452 return 1;
453 ma_net_clear(net);
454 net->extension->multi_status= status;
455 return 0;
456 case COM_MULTI_DISABLED:
457 /* Opposite to COM_MULTI_OFF we don't clear net buffer,
458 next command or com_nulti_end will flush entire buffer */
459 net->extension->multi_status= status;
460 return 0;
461 case COM_MULTI_END:
462 {
463 size_t len= net->write_pos - net->buff - NET_HEADER_SIZE;
464
465 if (len < NET_HEADER_SIZE) /* don't send empty COM_MULTI */
466 {
467 ma_net_clear(net);
468 return 1;
469 }
470 net->extension->multi_status= COM_MULTI_OFF;
471 return ma_net_flush(net);
472 }
473 case COM_MULTI_CANCEL:
474 ma_net_clear(net);
475 net->extension->multi_status= COM_MULTI_OFF;
476 return 0;
477 default:
478 return 1;
479 }
480}
481
482static void free_old_query(MYSQL *mysql)
483{
484 if (mysql->fields)
485 ma_free_root(&mysql->field_alloc,MYF(0));
486 ma_init_alloc_root(&mysql->field_alloc,8192,0); /* Assume rowlength < 8192 */
487 mysql->fields=0;
488 mysql->field_count=0; /* For API */
489 mysql->info= 0;
490 return;
491}
492
493#if defined(HAVE_GETPWUID) && defined(NO_GETPWUID_DECL)
494struct passwd *getpwuid(uid_t);
495char* getlogin(void);
496#endif
497
498#if !defined(MSDOS) && ! defined(VMS) && !defined(_WIN32) && !defined(OS2)
499void read_user_name(char *name)
500{
501 if (geteuid() == 0)
502 strcpy(name,"root"); /* allow use of surun */
503 else
504 {
505#ifdef HAVE_GETPWUID
506 struct passwd *skr;
507 const char *str;
508 if ((str=getlogin()) == NULL)
509 {
510 if ((skr=getpwuid(geteuid())) != NULL)
511 str=skr->pw_name;
512 else if (!(str=getenv("USER")) && !(str=getenv("LOGNAME")) &&
513 !(str=getenv("LOGIN")))
514 str="UNKNOWN_USER";
515 }
516 ma_strmake(name,str,USERNAME_LENGTH);
517#elif defined(HAVE_CUSERID)
518 (void) cuserid(name);
519#else
520 ma_strmake(name,"UNKNOWN_USER", USERNAME_LENGTH);
521#endif
522 }
523 return;
524}
525
526#else /* If MSDOS || VMS */
527
528void read_user_name(char *name)
529{
530 char *str=getenv("USERNAME"); /* ODBC will send user variable */
531 ma_strmake(name,str ? str : "ODBC", USERNAME_LENGTH);
532}
533
534#endif
535
536
537/**************************************************************************
538** Shut down connection
539**************************************************************************/
540
541static void
542end_server(MYSQL *mysql)
543{
544 /* if net->error 2 and reconnect is activated, we need to inforn
545 connection handler */
546 if (mysql->net.pvio != 0)
547 {
548 ma_pvio_close(mysql->net.pvio);
549 mysql->net.pvio= 0; /* Marker */
550 }
551 ma_net_end(&mysql->net);
552 free_old_query(mysql);
553 return;
554}
555
556void mthd_my_skip_result(MYSQL *mysql)
557{
558 ulong pkt_len;
559
560 do {
561 pkt_len= ma_net_safe_read(mysql);
562 if (pkt_len == packet_error)
563 break;
564 } while (pkt_len > 8 || mysql->net.read_pos[0] != 254);
565 return;
566}
567
568void STDCALL
569mysql_free_result(MYSQL_RES *result)
570{
571 if (result)
572 {
573 if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT)
574 {
575 result->handle->methods->db_skip_result(result->handle);
576 result->handle->status=MYSQL_STATUS_READY;
577 }
578 free_rows(result->data);
579 if (result->fields)
580 ma_free_root(&result->field_alloc,MYF(0));
581 if (result->row)
582 free(result->row);
583 free(result);
584 }
585 return;
586}
587
588
589/****************************************************************************
590** Get options from my.cnf
591****************************************************************************/
592enum enum_option_type {
593 MARIADB_OPTION_NONE,
594 MARIADB_OPTION_BOOL,
595 MARIADB_OPTION_INT,
596 MARIADB_OPTION_SIZET,
597 MARIADB_OPTION_STR,
598};
599
600struct st_default_options {
601 enum mysql_option option;
602 enum enum_option_type type;
603 const char *conf_key;
604};
605
606struct st_default_options mariadb_defaults[] =
607{
608 {MARIADB_OPT_PORT, MARIADB_OPTION_INT,"port"},
609 {MARIADB_OPT_UNIXSOCKET, MARIADB_OPTION_STR, "socket"},
610 {MYSQL_OPT_COMPRESS, MARIADB_OPTION_BOOL, "compress"},
611 {MARIADB_OPT_PASSWORD, MARIADB_OPTION_STR, "password"},
612 {MYSQL_OPT_NAMED_PIPE, MARIADB_OPTION_BOOL, "pipe"},
613 {MYSQL_OPT_CONNECT_TIMEOUT, MARIADB_OPTION_INT, "timeout"},
614 {MARIADB_OPT_USER, MARIADB_OPTION_STR, "user"},
615 {MYSQL_INIT_COMMAND, MARIADB_OPTION_STR, "init-command"},
616 {MARIADB_OPT_HOST, MARIADB_OPTION_STR, "host"},
617 {MARIADB_OPT_SCHEMA, MARIADB_OPTION_STR, "database"},
618 {MARIADB_OPT_DEBUG, MARIADB_OPTION_STR, "debug"},
619 {MARIADB_OPT_FOUND_ROWS, MARIADB_OPTION_NONE, "return-found-rows"},
620 {MYSQL_OPT_SSL_KEY, MARIADB_OPTION_STR, "ssl-key"},
621 {MYSQL_OPT_SSL_CERT, MARIADB_OPTION_STR,"ssl-cert"},
622 {MYSQL_OPT_SSL_CA, MARIADB_OPTION_STR,"ssl-ca"},
623 {MYSQL_OPT_SSL_CAPATH, MARIADB_OPTION_STR,"ssl-capath"},
624 {MYSQL_OPT_SSL_CRL, MARIADB_OPTION_STR,"ssl-crl"},
625 {MYSQL_OPT_SSL_CRLPATH, MARIADB_OPTION_STR,"ssl-crlpath"},
626 {MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MARIADB_OPTION_BOOL,"ssl-verify-server-cert"},
627 {MYSQL_SET_CHARSET_DIR, MARIADB_OPTION_STR, "character-sets-dir"},
628 {MYSQL_SET_CHARSET_NAME, MARIADB_OPTION_STR, "default-character-set"},
629 {MARIADB_OPT_INTERACTIVE, MARIADB_OPTION_NONE, "interactive-timeout"},
630 {MYSQL_OPT_CONNECT_TIMEOUT, MARIADB_OPTION_INT, "connect-timeout"},
631 {MYSQL_OPT_LOCAL_INFILE, MARIADB_OPTION_BOOL, "local-infile"},
632 {0, 0 ,"disable-local-infile",},
633 {MYSQL_OPT_SSL_CIPHER, MARIADB_OPTION_STR, "ssl-cipher"},
634 {MYSQL_OPT_MAX_ALLOWED_PACKET, MARIADB_OPTION_SIZET, "max-allowed-packet"},
635 {MYSQL_OPT_NET_BUFFER_LENGTH, MARIADB_OPTION_SIZET, "net-buffer-length"},
636 {MYSQL_OPT_PROTOCOL, MARIADB_OPTION_INT, "protocol"},
637 {MYSQL_SHARED_MEMORY_BASE_NAME, MARIADB_OPTION_STR,"shared-memory-base-name"},
638 {MARIADB_OPT_MULTI_RESULTS, MARIADB_OPTION_NONE, "multi-results"},
639 {MARIADB_OPT_MULTI_STATEMENTS, MARIADB_OPTION_STR, "multi-statements"},
640 {MARIADB_OPT_MULTI_STATEMENTS, MARIADB_OPTION_STR, "multi-queries"},
641 {MYSQL_SECURE_AUTH, MARIADB_OPTION_BOOL, "secure-auth"},
642 {MYSQL_REPORT_DATA_TRUNCATION, MARIADB_OPTION_BOOL, "report-data-truncation"},
643 {MYSQL_OPT_RECONNECT, MARIADB_OPTION_BOOL, "reconnect"},
644 {MYSQL_PLUGIN_DIR, MARIADB_OPTION_STR, "plugin-dir"},
645 {MYSQL_DEFAULT_AUTH, MARIADB_OPTION_STR, "default-auth"},
646 {MARIADB_OPT_SSL_FP, MARIADB_OPTION_STR, "ssl-fp"},
647 {MARIADB_OPT_SSL_FP_LIST, MARIADB_OPTION_STR, "ssl-fp-list"},
648 {MARIADB_OPT_SSL_FP_LIST, MARIADB_OPTION_STR, "ssl-fplist"},
649 {MARIADB_OPT_TLS_PASSPHRASE, MARIADB_OPTION_STR, "ssl-passphrase"},
650 {MARIADB_OPT_TLS_VERSION, MARIADB_OPTION_STR, "tls-version"},
651 {MYSQL_SERVER_PUBLIC_KEY, MARIADB_OPTION_STR, "server-public-key"},
652 {MYSQL_OPT_BIND, MARIADB_OPTION_STR, "bind-address"},
653 {MYSQL_OPT_SSL_ENFORCE, MARIADB_OPTION_BOOL, "ssl-enforce"},
654 {0, 0, NULL}
655};
656
657#define CHECK_OPT_EXTENSION_SET(OPTS)\
658 if (!(OPTS)->extension) \
659 (OPTS)->extension= (struct st_mysql_options_extension *) \
660 calloc(1, sizeof(struct st_mysql_options_extension));
661
662#define OPT_SET_EXTENDED_VALUE_STR(OPTS, KEY, VAL) \
663 CHECK_OPT_EXTENSION_SET(OPTS) \
664 free((gptr)(OPTS)->extension->KEY); \
665 if((VAL)) \
666 (OPTS)->extension->KEY= strdup((char *)(VAL)); \
667 else \
668 (OPTS)->extension->KEY= NULL
669
670#define OPT_SET_EXTENDED_VALUE(OPTS, KEY, VAL) \
671 CHECK_OPT_EXTENSION_SET(OPTS) \
672 (OPTS)->extension->KEY= (VAL)
673
674#define OPT_SET_EXTENDED_VALUE_INT(A,B,C) OPT_SET_EXTENDED_VALUE(A,B,C)
675
676#define OPT_SET_VALUE_STR(OPTS, KEY, VAL) \
677 free((OPTS)->KEY); \
678 if((VAL)) \
679 (OPTS)->KEY= strdup((char *)(VAL)); \
680 else \
681 (OPTS)->KEY= NULL
682
683#define OPT_SET_VALUE_INT(OPTS, KEY, VAL) \
684 (OPTS)->KEY= (VAL)
685
686static void options_add_initcommand(struct st_mysql_options *options,
687 const char *init_cmd)
688{
689 char *insert= strdup(init_cmd);
690 if (!options->init_command)
691 {
692 options->init_command= (DYNAMIC_ARRAY*)malloc(sizeof(DYNAMIC_ARRAY));
693 ma_init_dynamic_array(options->init_command, sizeof(char*), 5, 5);
694 }
695
696 if (ma_insert_dynamic(options->init_command, (gptr)&insert))
697 free(insert);
698}
699my_bool _mariadb_set_conf_option(MYSQL *mysql, const char *config_option, const char *config_value)
700{
701 if (config_option)
702 {
703 int i;
704 char *c;
705
706 /* CONC-395: replace underscore "_" by dash "-" */
707 while ((c= strchr(config_option, '_')))
708 *c= '-';
709
710 for (i=0; mariadb_defaults[i].conf_key; i++)
711 {
712 if (!strcmp(mariadb_defaults[i].conf_key, config_option))
713 {
714 my_bool val_bool;
715 int val_int;
716 size_t val_sizet;
717 int rc;
718 void *option_val= NULL;
719 switch (mariadb_defaults[i].type) {
720 case MARIADB_OPTION_BOOL:
721 val_bool= 0;
722 if (config_value)
723 val_bool= atoi(config_value);
724 option_val= &val_bool;
725 break;
726 case MARIADB_OPTION_INT:
727 val_int= 0;
728 if (config_value)
729 val_int= atoi(config_value);
730 option_val= &val_int;
731 break;
732 case MARIADB_OPTION_SIZET:
733 val_sizet= 0;
734 if (config_value)
735 val_sizet= strtol(config_value, NULL, 10);
736 option_val= &val_sizet;
737 break;
738 case MARIADB_OPTION_STR:
739 option_val= (void*)config_value;
740 break;
741 case MARIADB_OPTION_NONE:
742 break;
743 }
744 rc= mysql_optionsv(mysql, mariadb_defaults[i].option, option_val);
745 return(test(rc));
746 }
747 }
748 }
749 /* unknown key */
750 return 1;
751}
752
753/***************************************************************************
754** Change field rows to field structs
755***************************************************************************/
756
757static size_t rset_field_offsets[]= {
758 OFFSET(MYSQL_FIELD, catalog),
759 OFFSET(MYSQL_FIELD, catalog_length),
760 OFFSET(MYSQL_FIELD, db),
761 OFFSET(MYSQL_FIELD, db_length),
762 OFFSET(MYSQL_FIELD, table),
763 OFFSET(MYSQL_FIELD, table_length),
764 OFFSET(MYSQL_FIELD, org_table),
765 OFFSET(MYSQL_FIELD, org_table_length),
766 OFFSET(MYSQL_FIELD, name),
767 OFFSET(MYSQL_FIELD, name_length),
768 OFFSET(MYSQL_FIELD, org_name),
769 OFFSET(MYSQL_FIELD, org_name_length)
770};
771
772MYSQL_FIELD *
773unpack_fields(MYSQL_DATA *data,MA_MEM_ROOT *alloc,uint fields,
774 my_bool default_value, my_bool long_flag_protocol __attribute__((unused)))
775{
776 MYSQL_ROWS *row;
777 MYSQL_FIELD *field,*result;
778 char *p;
779 unsigned int i, field_count= sizeof(rset_field_offsets)/sizeof(size_t)/2;
780
781 field=result=(MYSQL_FIELD*) ma_alloc_root(alloc,sizeof(MYSQL_FIELD)*fields);
782 if (!result)
783 return(0);
784
785 for (row=data->data; row ; row = row->next,field++)
786 {
787 if (field >= result + fields)
788 goto error;
789
790 for (i=0; i < field_count; i++)
791 {
792 switch(row->data[i][0]) {
793 case 0:
794 *(char **)(((char *)field) + rset_field_offsets[i*2])= ma_strdup_root(alloc, "");
795 *(unsigned int *)(((char *)field) + rset_field_offsets[i*2+1])= 0;
796 break;
797 default:
798 *(char **)(((char *)field) + rset_field_offsets[i*2])=
799 ma_strdup_root(alloc, (char *)row->data[i]);
800 *(unsigned int *)(((char *)field) + rset_field_offsets[i*2+1])=
801 (uint)(row->data[i+1] - row->data[i] - 1);
802 break;
803 }
804 }
805
806 p= (char *)row->data[6];
807 /* filler */
808 field->charsetnr= uint2korr(p);
809 p+= 2;
810 field->length= (uint) uint4korr(p);
811 p+= 4;
812 field->type= (enum enum_field_types)uint1korr(p);
813 p++;
814 field->flags= uint2korr(p);
815 p+= 2;
816 field->decimals= (uint) p[0];
817 p++;
818
819 /* filler */
820 p+= 2;
821
822 if (INTERNAL_NUM_FIELD(field))
823 field->flags|= NUM_FLAG;
824
825 /* This is used by deprecated function mysql_list_fields only,
826 however the reported length is not correct, so we always zero it */
827 if (default_value && row->data[7])
828 field->def=ma_strdup_root(alloc,(char*) row->data[7]);
829 else
830 field->def=0;
831 field->def_length= 0;
832
833 field->max_length= 0;
834 }
835 if (field < result + fields)
836 goto error;
837 free_rows(data); /* Free old data */
838 return(result);
839error:
840 free_rows(data);
841 ma_free_root(alloc, MYF(0));
842 return(0);
843}
844
845
846/* Read all rows (fields or data) from server */
847
848MYSQL_DATA *mthd_my_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
849 uint fields)
850{
851 uint field;
852 ulong pkt_len;
853 ulong len;
854 uchar *cp;
855 char *to, *end_to;
856 MYSQL_DATA *result;
857 MYSQL_ROWS **prev_ptr,*cur;
858 NET *net = &mysql->net;
859
860 if ((pkt_len= ma_net_safe_read(mysql)) == packet_error)
861 return(0);
862 if (!(result=(MYSQL_DATA*) calloc(1, sizeof(MYSQL_DATA))))
863 {
864 SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
865 return(0);
866 }
867 ma_init_alloc_root(&result->alloc,8192,0); /* Assume rowlength < 8192 */
868 result->alloc.min_malloc=sizeof(MYSQL_ROWS);
869 prev_ptr= &result->data;
870 result->rows=0;
871 result->fields=fields;
872
873 while (*(cp=net->read_pos) != 254 || pkt_len >= 8)
874 {
875 result->rows++;
876 if (!(cur= (MYSQL_ROWS*) ma_alloc_root(&result->alloc,
877 sizeof(MYSQL_ROWS))) ||
878 !(cur->data= ((MYSQL_ROW)
879 ma_alloc_root(&result->alloc,
880 (fields+1)*sizeof(char *)+fields+pkt_len))))
881 {
882 free_rows(result);
883 SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
884 return(0);
885 }
886 *prev_ptr=cur;
887 prev_ptr= &cur->next;
888 to= (char*) (cur->data+fields+1);
889 end_to=to+fields+pkt_len-1;
890 for (field=0 ; field < fields ; field++)
891 {
892 if ((len=(ulong) net_field_length(&cp)) == NULL_LENGTH)
893 { /* null field */
894 cur->data[field] = 0;
895 }
896 else
897 {
898 cur->data[field] = to;
899 if (len > (ulong)(end_to - to) || to > end_to)
900 {
901 free_rows(result);
902 SET_CLIENT_ERROR(mysql, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, 0);
903 return(0);
904 }
905 memcpy(to,(char*) cp,len); to[len]=0;
906 to+=len+1;
907 cp+=len;
908 if (mysql_fields)
909 {
910 if (mysql_fields[field].max_length < len)
911 mysql_fields[field].max_length=len;
912 }
913 }
914 }
915 cur->data[field]=to; /* End of last field */
916 if ((pkt_len=ma_net_safe_read(mysql)) == packet_error)
917 {
918 free_rows(result);
919 return(0);
920 }
921 }
922 *prev_ptr=0; /* last pointer is null */
923 /* save status */
924 if (pkt_len > 1)
925 {
926 cp++;
927 mysql->warning_count= uint2korr(cp);
928 cp+= 2;
929 mysql->server_status= uint2korr(cp);
930 }
931 return(result);
932}
933
934
935/*
936** Read one row. Uses packet buffer as storage for fields.
937** When next packet is read, the previous field values are destroyed
938*/
939
940
941int mthd_my_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
942{
943 uint field;
944 ulong pkt_len,len;
945 uchar *pos,*prev_pos, *end_pos;
946
947 if ((pkt_len=(uint) ma_net_safe_read(mysql)) == packet_error)
948 return -1;
949
950 if (pkt_len <= 8 && mysql->net.read_pos[0] == 254)
951 {
952 mysql->warning_count= uint2korr(mysql->net.read_pos + 1);
953 mysql->server_status= uint2korr(mysql->net.read_pos + 3);
954 return 1; /* End of data */
955 }
956 prev_pos= 0; /* allowed to write at packet[-1] */
957 pos=mysql->net.read_pos;
958 end_pos=pos+pkt_len;
959 for (field=0 ; field < fields ; field++)
960 {
961 if ((len=(ulong) net_field_length(&pos)) == NULL_LENGTH)
962 { /* null field */
963 row[field] = 0;
964 *lengths++=0;
965 }
966 else
967 {
968 if (len > (ulong) (end_pos - pos) || pos > end_pos)
969 {
970 mysql->net.last_errno=CR_UNKNOWN_ERROR;
971 strncpy(mysql->net.last_error,ER(mysql->net.last_errno),
972 MYSQL_ERRMSG_SIZE - 1);
973 return -1;
974 }
975 row[field] = (char*) pos;
976 pos+=len;
977 *lengths++=len;
978 }
979 if (prev_pos)
980 *prev_pos=0; /* Terminate prev field */
981 prev_pos=pos;
982 }
983 row[field]=(char*) prev_pos+1; /* End of last field */
984 *prev_pos=0; /* Terminate last field */
985 return 0;
986}
987
988/****************************************************************************
989** Init MySQL structure or allocate one
990****************************************************************************/
991
992MYSQL * STDCALL
993mysql_init(MYSQL *mysql)
994{
995 if (mysql_server_init(0, NULL, NULL))
996 return NULL;
997 if (!mysql)
998 {
999 if (!(mysql=(MYSQL*) calloc(1, sizeof(MYSQL))))
1000 return 0;
1001 mysql->free_me=1;
1002 mysql->net.pvio= 0;
1003 mysql->net.extension= 0;
1004 }
1005 else
1006 {
1007 memset((char*) (mysql), 0, sizeof(*(mysql)));
1008 mysql->net.pvio= 0;
1009 mysql->free_me= 0;
1010 mysql->net.extension= 0;
1011 }
1012
1013 if (!(mysql->net.extension= (struct st_mariadb_net_extension *)
1014 calloc(1, sizeof(struct st_mariadb_net_extension))) ||
1015 !(mysql->extension= (struct st_mariadb_extension *)
1016 calloc(1, sizeof(struct st_mariadb_extension))))
1017 goto error;
1018 mysql->options.report_data_truncation= 1;
1019 mysql->options.connect_timeout=CONNECT_TIMEOUT;
1020 mysql->charset= mysql_find_charset_name(MARIADB_DEFAULT_CHARSET);
1021 mysql->methods= &MARIADB_DEFAULT_METHODS;
1022 strcpy(mysql->net.sqlstate, "00000");
1023 mysql->net.last_error[0]= mysql->net.last_errno= 0;
1024
1025 if (ENABLED_LOCAL_INFILE != LOCAL_INFILE_MODE_OFF)
1026 mysql->options.client_flag|= CLIENT_LOCAL_FILES;
1027 mysql->extension->auto_local_infile= ENABLED_LOCAL_INFILE == LOCAL_INFILE_MODE_AUTO
1028 ? WAIT_FOR_QUERY : ALWAYS_ACCEPT;
1029 mysql->options.reconnect= 0;
1030 return mysql;
1031error:
1032 if (mysql->free_me)
1033 free(mysql);
1034 return 0;
1035}
1036
1037int STDCALL
1038mysql_ssl_set(MYSQL *mysql __attribute__((unused)),
1039 const char *key __attribute__((unused)),
1040 const char *cert __attribute__((unused)),
1041 const char *ca __attribute__((unused)),
1042 const char *capath __attribute__((unused)),
1043 const char *cipher __attribute__((unused)))
1044{
1045#ifdef HAVE_TLS
1046 char enable= 1;
1047 return (mysql_optionsv(mysql, MYSQL_OPT_SSL_ENFORCE, &enable) |
1048 mysql_optionsv(mysql, MYSQL_OPT_SSL_KEY, key) |
1049 mysql_optionsv(mysql, MYSQL_OPT_SSL_CERT, cert) |
1050 mysql_optionsv(mysql, MYSQL_OPT_SSL_CA, ca) |
1051 mysql_optionsv(mysql, MYSQL_OPT_SSL_CAPATH, capath) |
1052 mysql_optionsv(mysql, MYSQL_OPT_SSL_CIPHER, cipher)) ? 1 : 0;
1053#else
1054 return 0;
1055#endif
1056}
1057
1058/**************************************************************************
1059**************************************************************************/
1060
1061const char * STDCALL
1062mysql_get_ssl_cipher(MYSQL *mysql __attribute__((unused)))
1063{
1064#ifdef HAVE_TLS
1065 if (mysql->net.pvio && mysql->net.pvio->ctls)
1066 {
1067 return ma_pvio_tls_cipher(mysql->net.pvio->ctls);
1068 }
1069#endif
1070 return(NULL);
1071}
1072
1073/**************************************************************************
1074** Free strings in the SSL structure and clear 'use_ssl' flag.
1075** NB! Errors are not reported until you do mysql_real_connect.
1076**************************************************************************/
1077
1078char *ma_send_connect_attr(MYSQL *mysql, unsigned char *buffer)
1079{
1080 if (mysql->server_capabilities & CLIENT_CONNECT_ATTRS)
1081 {
1082 buffer= (unsigned char *)mysql_net_store_length((unsigned char *)buffer, (mysql->options.extension) ?
1083 mysql->options.extension->connect_attrs_len : 0);
1084 if (mysql->options.extension &&
1085 hash_inited(&mysql->options.extension->connect_attrs))
1086 {
1087 uint i;
1088 for (i=0; i < mysql->options.extension->connect_attrs.records; i++)
1089 {
1090 size_t len;
1091 uchar *p= hash_element(&mysql->options.extension->connect_attrs, i);
1092
1093 len= strlen((char *)p);
1094 buffer= mysql_net_store_length(buffer, len);
1095 memcpy(buffer, p, len);
1096 buffer+= (len);
1097 p+= (len + 1);
1098 len= strlen((char *)p);
1099 buffer= mysql_net_store_length(buffer, len);
1100 memcpy(buffer, p, len);
1101 buffer+= len;
1102 }
1103 }
1104 }
1105 return (char *)buffer;
1106}
1107
1108/** set some default attributes */
1109static my_bool
1110ma_set_connect_attrs(MYSQL *mysql, const char *host)
1111{
1112 char buffer[255];
1113 int rc= 0;
1114
1115 rc= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_client_name") +
1116 mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_client_version") +
1117 mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_os") +
1118 mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_server_host") +
1119#ifdef _WIN32
1120 mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_thread") +
1121#endif
1122 mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_pid") +
1123 mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_platform");
1124
1125 rc+= mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_client_name", "libmariadb")
1126 + mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_client_version", MARIADB_PACKAGE_VERSION)
1127 + mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_os", MARIADB_SYSTEM_TYPE);
1128
1129 if (host && *host)
1130 rc+= mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_server_host", host);
1131
1132#ifdef _WIN32
1133 snprintf(buffer, 255, "%lu", (ulong) GetCurrentThreadId());
1134 rc+= mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_thread", buffer);
1135 snprintf(buffer, 255, "%lu", (ulong) GetCurrentProcessId());
1136#else
1137 snprintf(buffer, 255, "%lu", (ulong) getpid());
1138#endif
1139 rc+= mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_pid", buffer);
1140
1141 rc+= mysql_optionsv(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_platform", MARIADB_MACHINE_TYPE);
1142 return(test(rc>0));
1143}
1144
1145/*
1146** Note that the mysql argument must be initialized with mysql_init()
1147** before calling mysql_real_connect !
1148*/
1149
1150MYSQL * STDCALL
1151mysql_real_connect(MYSQL *mysql, const char *host, const char *user,
1152 const char *passwd, const char *db,
1153 uint port, const char *unix_socket,unsigned long client_flag)
1154{
1155 char *end= NULL;
1156 char *connection_handler= (mysql->options.extension) ?
1157 mysql->options.extension->connection_handler : 0;
1158
1159 if (!mysql->methods)
1160 mysql->methods= &MARIADB_DEFAULT_METHODS;
1161
1162 if (connection_handler ||
1163 (host && (end= strstr(host, "://"))))
1164 {
1165 MARIADB_CONNECTION_PLUGIN *plugin;
1166 char plugin_name[64];
1167
1168 if (!connection_handler || !connection_handler[0])
1169 {
1170 memset(plugin_name, 0, 64);
1171 ma_strmake(plugin_name, host, MIN(end - host, 63));
1172 end+= 3;
1173 }
1174 else
1175 ma_strmake(plugin_name, connection_handler, MIN(63, strlen(connection_handler)));
1176
1177 if (!(plugin= (MARIADB_CONNECTION_PLUGIN *)mysql_client_find_plugin(mysql, plugin_name, MARIADB_CLIENT_CONNECTION_PLUGIN)))
1178 return NULL;
1179
1180 if (!(mysql->extension->conn_hdlr= (MA_CONNECTION_HANDLER *)calloc(1, sizeof(MA_CONNECTION_HANDLER))))
1181 {
1182 SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
1183 return NULL;
1184 }
1185
1186 /* save URL for reconnect */
1187 OPT_SET_EXTENDED_VALUE_STR(&mysql->options, url, host);
1188
1189 mysql->extension->conn_hdlr->plugin= plugin;
1190
1191 if (plugin && plugin->connect)
1192 {
1193 MYSQL *my= plugin->connect(mysql, end, user, passwd, db, port, unix_socket, client_flag);
1194 if (!my)
1195 {
1196 free(mysql->extension->conn_hdlr);
1197 mysql->extension->conn_hdlr= NULL;
1198 }
1199 return my;
1200 }
1201 }
1202
1203 return mysql->methods->db_connect(mysql, host, user, passwd,
1204 db, port, unix_socket, client_flag);
1205}
1206
1207MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user,
1208 const char *passwd, const char *db,
1209 uint port, const char *unix_socket, unsigned long client_flag)
1210{
1211 char buff[NAME_LEN+USERNAME_LENGTH+100];
1212 char *end, *end_pkt, *host_info;
1213 MA_PVIO_CINFO cinfo= {NULL, NULL, 0, -1, NULL};
1214 MARIADB_PVIO *pvio= NULL;
1215 char *scramble_data;
1216 my_bool is_maria= 0;
1217 const char *scramble_plugin;
1218 uint pkt_length, scramble_len, pkt_scramble_len= 0;
1219 NET *net= &mysql->net;
1220
1221 if (!mysql->methods)
1222 mysql->methods= &MARIADB_DEFAULT_METHODS;
1223
1224 if (net->pvio) /* check if we are already connected */
1225 {
1226 SET_CLIENT_ERROR(mysql, CR_ALREADY_CONNECTED, SQLSTATE_UNKNOWN, 0);
1227 return(NULL);
1228 }
1229
1230 /* use default options */
1231 if (mysql->options.my_cnf_file || mysql->options.my_cnf_group)
1232 {
1233 _mariadb_read_options(mysql, NULL,
1234 (mysql->options.my_cnf_file ?
1235 mysql->options.my_cnf_file : NULL),
1236 mysql->options.my_cnf_group, 0);
1237 free(mysql->options.my_cnf_file);
1238 free(mysql->options.my_cnf_group);
1239 mysql->options.my_cnf_file=mysql->options.my_cnf_group=0;
1240 }
1241
1242 if (!host || !host[0])
1243 host = mysql->options.host;
1244
1245 ma_set_connect_attrs(mysql, host);
1246
1247#ifndef WIN32
1248 if (mysql->options.protocol > MYSQL_PROTOCOL_SOCKET)
1249 {
1250 SET_CLIENT_ERROR(mysql, CR_CONN_UNKNOWN_PROTOCOL, SQLSTATE_UNKNOWN, 0);
1251 return(NULL);
1252 }
1253#endif
1254
1255 /* Some empty-string-tests are done because of ODBC */
1256 if (!user || !user[0])
1257 user=mysql->options.user;
1258 if (!passwd)
1259 {
1260 passwd=mysql->options.password;
1261#ifndef DONT_USE_MYSQL_PWD
1262 if (!passwd)
1263 passwd=getenv("MYSQL_PWD"); /* get it from environment (haneke) */
1264 if (!passwd)
1265 passwd= "";
1266#endif
1267 }
1268 if (!db || !db[0])
1269 db=mysql->options.db;
1270 if (!port)
1271 port=mysql->options.port;
1272 if (!unix_socket)
1273 unix_socket=mysql->options.unix_socket;
1274
1275 mysql->server_status=SERVER_STATUS_AUTOCOMMIT;
1276
1277 /* try to connect via pvio_init */
1278 cinfo.host= host;
1279 cinfo.unix_socket= unix_socket;
1280 cinfo.port= port;
1281 cinfo.mysql= mysql;
1282
1283 /*
1284 ** Grab a socket and connect it to the server
1285 */
1286#ifndef _WIN32
1287#if defined(HAVE_SYS_UN_H)
1288 if ((!host || strcmp(host,LOCAL_HOST) == 0) &&
1289 mysql->options.protocol != MYSQL_PROTOCOL_TCP &&
1290 (unix_socket || mysql_unix_port))
1291 {
1292 cinfo.host= LOCAL_HOST;
1293 cinfo.unix_socket= (unix_socket) ? unix_socket : mysql_unix_port;
1294 cinfo.type= PVIO_TYPE_UNIXSOCKET;
1295 sprintf(host_info=buff,ER(CR_LOCALHOST_CONNECTION),cinfo.host);
1296 }
1297 else
1298#endif
1299#else
1300 if (mysql->options.protocol == MYSQL_PROTOCOL_MEMORY)
1301 {
1302 cinfo.host= mysql->options.shared_memory_base_name;
1303 cinfo.type= PVIO_TYPE_SHAREDMEM;
1304 sprintf(host_info=buff,ER(CR_SHARED_MEMORY_CONNECTION), cinfo.host ? cinfo.host : SHM_DEFAULT_NAME);
1305 }
1306 /* named pipe */
1307 else if (mysql->options.protocol == MYSQL_PROTOCOL_PIPE ||
1308 (host && strcmp(host,LOCAL_HOST_NAMEDPIPE) == 0))
1309 {
1310 cinfo.type= PVIO_TYPE_NAMEDPIPE;
1311 sprintf(host_info=buff,ER(CR_NAMEDPIPE_CONNECTION),cinfo.host);
1312 }
1313 else
1314#endif
1315 {
1316 cinfo.unix_socket=0; /* This is not used */
1317 if (!port)
1318 port=mysql_port;
1319 if (!host)
1320 host=LOCAL_HOST;
1321 cinfo.host= host;
1322 cinfo.port= port;
1323 cinfo.type= PVIO_TYPE_SOCKET;
1324 sprintf(host_info=buff,ER(CR_TCP_CONNECTION), cinfo.host);
1325 }
1326 /* Initialize and load pvio plugin */
1327 if (!(pvio= ma_pvio_init(&cinfo)))
1328 goto error;
1329
1330 /* try to connect */
1331 if (ma_pvio_connect(pvio, &cinfo) != 0)
1332 {
1333 ma_pvio_close(pvio);
1334 goto error;
1335 }
1336
1337 if (mysql->options.extension && mysql->options.extension->proxy_header)
1338 {
1339 char *hdr = mysql->options.extension->proxy_header;
1340 size_t len = mysql->options.extension->proxy_header_len;
1341 if (ma_pvio_write(pvio, (unsigned char *)hdr, len) <= 0)
1342 {
1343 ma_pvio_close(pvio);
1344 goto error;
1345 }
1346 }
1347
1348 if (ma_net_init(net, pvio))
1349 goto error;
1350
1351 if (mysql->options.max_allowed_packet)
1352 net->max_packet_size= mysql->options.max_allowed_packet;
1353
1354 ma_pvio_keepalive(net->pvio);
1355 strcpy(mysql->net.sqlstate, "00000");
1356
1357 /* Get version info */
1358 mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */
1359/*
1360 if (ma_pvio_wait_io_or_timeout(net->pvio, FALSE, 0) < 1)
1361 {
1362 my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
1363 ER(CR_SERVER_LOST_EXTENDED),
1364 "handshake: waiting for inital communication packet",
1365 errno);
1366 goto error;
1367 }
1368 */
1369 if ((pkt_length=ma_net_safe_read(mysql)) == packet_error)
1370 {
1371 if (mysql->net.last_errno == CR_SERVER_LOST)
1372 my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
1373 ER(CR_SERVER_LOST_EXTENDED),
1374 "handshake: reading inital communication packet",
1375 errno);
1376
1377 goto error;
1378 }
1379 end= (char *)net->read_pos;
1380 end_pkt= (char *)net->read_pos + pkt_length;
1381
1382 /* Check if version of protocol matches current one */
1383
1384 mysql->protocol_version= end[0];
1385 end++;
1386
1387 /* Check if server sends an error */
1388 if (mysql->protocol_version == 0XFF)
1389 {
1390 net_get_error(end, pkt_length - 1, net->last_error, sizeof(net->last_error),
1391 &net->last_errno, net->sqlstate);
1392 /* fix for bug #26426 */
1393 if (net->last_errno == 1040)
1394 memcpy(net->sqlstate, "08004", SQLSTATE_LENGTH);
1395 goto error;
1396 }
1397
1398 if (mysql->protocol_version < PROTOCOL_VERSION)
1399 {
1400 net->last_errno= CR_VERSION_ERROR;
1401 sprintf(net->last_error, ER(CR_VERSION_ERROR), mysql->protocol_version,
1402 PROTOCOL_VERSION);
1403 goto error;
1404 }
1405 /* Save connection information */
1406 if (!user) user="";
1407
1408 if (!(mysql->host_info= strdup(host_info)) ||
1409 !(mysql->host= strdup(cinfo.host ? cinfo.host : "")) ||
1410 !(mysql->user=strdup(user)) ||
1411 !(mysql->passwd=strdup(passwd)))
1412 {
1413 SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
1414 goto error;
1415 }
1416 if (cinfo.unix_socket)
1417 mysql->unix_socket= strdup(cinfo.unix_socket);
1418 else
1419 mysql->unix_socket=0;
1420 mysql->port=port;
1421 client_flag|=mysql->options.client_flag;
1422
1423 if (strncmp(end, MA_RPL_VERSION_HACK, sizeof(MA_RPL_VERSION_HACK) - 1) == 0)
1424 {
1425 mysql->server_version= strdup(end + sizeof(MA_RPL_VERSION_HACK) - 1);
1426 is_maria= 1;
1427 }
1428 else
1429 {
1430 if (!(mysql->server_version= strdup(end)))
1431 {
1432 SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
1433 goto error;
1434 }
1435 }
1436 end+= strlen(end) + 1;
1437
1438 mysql->thread_id=uint4korr(end);
1439 end+=4;
1440
1441 /* This is the first part of scramble packet. In 4.1 and later
1442 a second package will follow later */
1443 scramble_data= end;
1444 scramble_len= SCRAMBLE_LENGTH_323 + 1;
1445 scramble_plugin= old_password_plugin_name;
1446 end+= SCRAMBLE_LENGTH_323;
1447
1448 /* 1st pad */
1449 end++;
1450
1451 if (end + 1<= end_pkt)
1452 {
1453 mysql->server_capabilities=uint2korr(end);
1454 }
1455
1456 /* mysql 5.5 protocol */
1457 if (end + 18 <= end_pkt)
1458 {
1459 mysql->server_language= uint1korr(end + 2);
1460 mysql->server_status= uint2korr(end + 3);
1461 mysql->server_capabilities|= (unsigned int)(uint2korr(end + 5)) << 16;
1462 pkt_scramble_len= uint1korr(end + 7);
1463
1464 /* check if MariaD2B specific capabilities are available */
1465 if (is_maria && !(mysql->server_capabilities & CLIENT_MYSQL))
1466 {
1467 mysql->extension->mariadb_server_capabilities= (ulonglong) uint4korr(end + 14);
1468 }
1469 }
1470
1471 /* pad 2 */
1472 end+= 18;
1473
1474 /* second scramble package */
1475 if (end + SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1 <= end_pkt)
1476 {
1477 memcpy(end - SCRAMBLE_LENGTH_323, scramble_data, SCRAMBLE_LENGTH_323);
1478 scramble_data= end - SCRAMBLE_LENGTH_323;
1479 if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
1480 {
1481 scramble_len= pkt_scramble_len;
1482 scramble_plugin= scramble_data + scramble_len;
1483 if (scramble_data + scramble_len > end_pkt)
1484 scramble_len= (uint)(end_pkt - scramble_data);
1485 } else
1486 {
1487 scramble_len= (uint)(end_pkt - scramble_data);
1488 scramble_plugin= native_password_plugin_name;
1489 }
1490 } else
1491 {
1492 mysql->server_capabilities&= ~CLIENT_SECURE_CONNECTION;
1493 if (mysql->options.secure_auth)
1494 {
1495 SET_CLIENT_ERROR(mysql, CR_SECURE_AUTH, SQLSTATE_UNKNOWN, 0);
1496 goto error;
1497 }
1498 }
1499
1500 /* Set character set */
1501 if (mysql->options.charset_name)
1502 mysql->charset= mysql_find_charset_name(mysql->options.charset_name);
1503 else
1504 mysql->charset=mysql_find_charset_name(MARIADB_DEFAULT_CHARSET);
1505
1506 if (!mysql->charset)
1507 {
1508 net->last_errno=CR_CANT_READ_CHARSET;
1509 sprintf(net->last_error,ER(net->last_errno),
1510 mysql->options.charset_name ? mysql->options.charset_name :
1511 MARIADB_DEFAULT_CHARSET,
1512 "compiled_in");
1513 goto error;
1514 }
1515
1516 mysql->client_flag= client_flag;
1517
1518 if (run_plugin_auth(mysql, scramble_data, scramble_len,
1519 scramble_plugin, db))
1520 goto error;
1521
1522 if (mysql->client_flag & CLIENT_COMPRESS)
1523 net->compress= 1;
1524
1525 /* last part: select default db */
1526 if (!(mysql->server_capabilities & CLIENT_CONNECT_WITH_DB) &&
1527 (db && !mysql->db))
1528 {
1529 if (mysql_select_db(mysql, db))
1530 {
1531 my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
1532 ER(CR_SERVER_LOST_EXTENDED),
1533 "Setting intital database",
1534 errno);
1535 goto error;
1536 }
1537 }
1538
1539 if (mysql->options.init_command)
1540 {
1541 char **begin= (char **)mysql->options.init_command->buffer;
1542 char **end= begin + mysql->options.init_command->elements;
1543
1544 /* Avoid reconnect in mysql_real_connect */
1545 my_bool save_reconnect= mysql->options.reconnect;
1546 mysql->options.reconnect= 0;
1547
1548 for (;begin < end; begin++)
1549 {
1550 if (mysql_real_query(mysql, *begin, (unsigned long)strlen(*begin)))
1551 goto error;
1552
1553 /* check if query produced a result set */
1554 do {
1555 MYSQL_RES *res;
1556 if ((res= mysql_use_result(mysql)))
1557 mysql_free_result(res);
1558 } while (!mysql_next_result(mysql));
1559 }
1560 mysql->options.reconnect= save_reconnect;
1561 }
1562
1563 strcpy(mysql->net.sqlstate, "00000");
1564
1565 /* connection established, apply timeouts */
1566 ma_pvio_set_timeout(mysql->net.pvio, PVIO_READ_TIMEOUT, mysql->options.read_timeout);
1567 ma_pvio_set_timeout(mysql->net.pvio, PVIO_WRITE_TIMEOUT, mysql->options.write_timeout);
1568 return(mysql);
1569
1570error:
1571 /* Free alloced memory */
1572 end_server(mysql);
1573 /* only free the allocated memory, user needs to call mysql_close */
1574 mysql_close_memory(mysql);
1575 if (!(client_flag & CLIENT_REMEMBER_OPTIONS) &&
1576 !mysql->options.extension->async_context)
1577 mysql_close_options(mysql);
1578 return(0);
1579}
1580
1581struct my_hook_data {
1582 MYSQL *orig_mysql;
1583 MYSQL *new_mysql;
1584 /* This is always NULL currently, but restoring does not hurt just in case. */
1585 MARIADB_PVIO *orig_pvio;
1586};
1587/*
1588 Callback hook to make the new VIO accessible via the old MYSQL to calling
1589 application when suspending a non-blocking call during automatic reconnect.
1590*/
1591static void
1592my_suspend_hook(my_bool suspend, void *data)
1593{
1594 struct my_hook_data *hook_data= (struct my_hook_data *)data;
1595 if (suspend)
1596 {
1597 hook_data->orig_pvio= hook_data->orig_mysql->net.pvio;
1598 hook_data->orig_mysql->net.pvio= hook_data->new_mysql->net.pvio;
1599 }
1600 else
1601 hook_data->orig_mysql->net.pvio= hook_data->orig_pvio;
1602}
1603
1604my_bool STDCALL mariadb_reconnect(MYSQL *mysql)
1605{
1606 MYSQL tmp_mysql;
1607 struct my_hook_data hook_data;
1608 struct mysql_async_context *ctxt= NULL;
1609 LIST *li_stmt= mysql->stmts;
1610
1611 /* check if connection handler is active */
1612 if (IS_CONNHDLR_ACTIVE(mysql))
1613 {
1614 if (mysql->extension->conn_hdlr->plugin && mysql->extension->conn_hdlr->plugin->reconnect)
1615 return(mysql->extension->conn_hdlr->plugin->reconnect(mysql));
1616 }
1617
1618 if (!mysql->options.reconnect ||
1619 (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info)
1620 {
1621 /* Allow reconnect next time */
1622 mysql->server_status&= ~SERVER_STATUS_IN_TRANS;
1623 my_set_error(mysql, CR_SERVER_GONE_ERROR, SQLSTATE_UNKNOWN, 0);
1624 return(1);
1625 }
1626
1627 mysql_init(&tmp_mysql);
1628 tmp_mysql.free_me= 0;
1629 tmp_mysql.options=mysql->options;
1630 if (mysql->extension->conn_hdlr)
1631 {
1632 tmp_mysql.extension->conn_hdlr= mysql->extension->conn_hdlr;
1633 mysql->extension->conn_hdlr= 0;
1634 }
1635
1636 /* don't reread options from configuration files */
1637 tmp_mysql.options.my_cnf_group= tmp_mysql.options.my_cnf_file= NULL;
1638 if (IS_MYSQL_ASYNC_ACTIVE(mysql))
1639 {
1640 ctxt= mysql->options.extension->async_context;
1641 hook_data.orig_mysql= mysql;
1642 hook_data.new_mysql= &tmp_mysql;
1643 hook_data.orig_pvio= mysql->net.pvio;
1644 my_context_install_suspend_resume_hook(ctxt, my_suspend_hook, &hook_data);
1645 }
1646
1647 if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
1648 mysql->db, mysql->port, mysql->unix_socket,
1649 mysql->client_flag | CLIENT_REMEMBER_OPTIONS) ||
1650 mysql_set_character_set(&tmp_mysql, mysql->charset->csname))
1651 {
1652 if (ctxt)
1653 my_context_install_suspend_resume_hook(ctxt, NULL, NULL);
1654 /* don't free options (CONC-118) */
1655 memset(&tmp_mysql.options, 0, sizeof(struct st_mysql_options));
1656 my_set_error(mysql, tmp_mysql.net.last_errno,
1657 tmp_mysql.net.sqlstate,
1658 tmp_mysql.net.last_error);
1659 mysql_close(&tmp_mysql);
1660 return(1);
1661 }
1662
1663 for (;li_stmt;li_stmt= li_stmt->next)
1664 {
1665 MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data;
1666
1667 if (stmt->state != MYSQL_STMT_INITTED)
1668 {
1669 stmt->state= MYSQL_STMT_INITTED;
1670 SET_CLIENT_STMT_ERROR(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0);
1671 }
1672 }
1673
1674 tmp_mysql.free_me= mysql->free_me;
1675 tmp_mysql.stmts= mysql->stmts;
1676 mysql->stmts= NULL;
1677
1678 if (ctxt)
1679 my_context_install_suspend_resume_hook(ctxt, NULL, NULL);
1680 /* Don't free options, we moved them to tmp_mysql */
1681 memset(&mysql->options, 0, sizeof(mysql->options));
1682 mysql->free_me=0;
1683 mysql_close(mysql);
1684 *mysql=tmp_mysql;
1685 mysql->net.pvio->mysql= mysql;
1686 ma_net_clear(&mysql->net);
1687 mysql->affected_rows= ~(unsigned long long) 0;
1688 mysql->info= 0;
1689 return(0);
1690}
1691
1692void ma_invalidate_stmts(MYSQL *mysql, const char *function_name)
1693{
1694 if (mysql->stmts)
1695 {
1696 LIST *li_stmt= mysql->stmts;
1697
1698 for (; li_stmt; li_stmt= li_stmt->next)
1699 {
1700 MYSQL_STMT *stmt= (MYSQL_STMT *)li_stmt->data;
1701 stmt->mysql= NULL;
1702 SET_CLIENT_STMT_ERROR(stmt, CR_STMT_CLOSED, SQLSTATE_UNKNOWN, function_name);
1703 }
1704 mysql->stmts= NULL;
1705 }
1706}
1707
1708/*
1709 Legacy support of the MariaDB 5.5 version, where timeouts where only in
1710 seconds resolution. Applications that use this will be asked to set a timeout
1711 at the nearest higher whole-seconds value.
1712*/
1713unsigned int STDCALL
1714mysql_get_timeout_value(const MYSQL *mysql)
1715{
1716 unsigned int timeout= mysql->options.extension->async_context->timeout_value;
1717 /* Avoid overflow. */
1718 if (timeout > UINT_MAX - 999)
1719 return (timeout - 1)/1000 + 1;
1720 else
1721 return (timeout+999)/1000;
1722}
1723
1724
1725unsigned int STDCALL
1726mysql_get_timeout_value_ms(const MYSQL *mysql)
1727{
1728 return mysql->options.extension->async_context->timeout_value;
1729}
1730
1731/**************************************************************************
1732** Change user and database
1733**************************************************************************/
1734
1735my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
1736 const char *passwd, const char *db)
1737{
1738 const MARIADB_CHARSET_INFO *s_cs= mysql->charset;
1739 char *s_user= mysql->user,
1740 *s_passwd= mysql->passwd,
1741 *s_db= mysql->db;
1742 int rc;
1743
1744 if (mysql->options.charset_name)
1745 mysql->charset= mysql_find_charset_name(mysql->options.charset_name);
1746 else
1747 mysql->charset=mysql_find_charset_name(MARIADB_DEFAULT_CHARSET);
1748
1749 mysql->user= strdup(user ? user : "");
1750 mysql->passwd= strdup(passwd ? passwd : "");
1751
1752 /* db will be set in run_plugin_auth */
1753 mysql->db= 0;
1754 rc= run_plugin_auth(mysql, 0, 0, 0, db);
1755
1756 /* COM_CHANGE_USER always releases prepared statements, so we need to invalidate them */
1757 ma_invalidate_stmts(mysql, "mysql_change_user()");
1758
1759 if (rc==0)
1760 {
1761 free(s_user);
1762 free(s_passwd);
1763 free(s_db);
1764
1765 if (!mysql->db && db && !(mysql->db= strdup(db)))
1766 {
1767 SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
1768 rc= 1;
1769 }
1770 } else
1771 {
1772 free(mysql->user);
1773 free(mysql->passwd);
1774 free(mysql->db);
1775
1776 mysql->user= s_user;
1777 mysql->passwd= s_passwd;
1778 mysql->db= s_db;
1779 mysql->charset= s_cs;
1780 }
1781 return(rc);
1782}
1783
1784
1785/**************************************************************************
1786** Set current database
1787**************************************************************************/
1788
1789int STDCALL
1790mysql_select_db(MYSQL *mysql, const char *db)
1791{
1792 int error;
1793
1794 if (!db)
1795 return 1;
1796
1797 if ((error=ma_simple_command(mysql, COM_INIT_DB, db,
1798 (uint) strlen(db),0,0)))
1799 return(error);
1800 free(mysql->db);
1801 mysql->db=strdup(db);
1802 return(0);
1803}
1804
1805
1806/*************************************************************************
1807** Send a QUIT to the server and close the connection
1808** If handle is alloced by mysql connect free it.
1809*************************************************************************/
1810
1811static void mysql_close_options(MYSQL *mysql)
1812{
1813 if (mysql->options.init_command)
1814 {
1815 char **begin= (char **)mysql->options.init_command->buffer;
1816 char **end= begin + mysql->options.init_command->elements;
1817
1818 for (;begin < end; begin++)
1819 free(*begin);
1820 ma_delete_dynamic(mysql->options.init_command);
1821 free(mysql->options.init_command);
1822 }
1823 free(mysql->options.user);
1824 free(mysql->options.host);
1825 free(mysql->options.password);
1826 free(mysql->options.unix_socket);
1827 free(mysql->options.db);
1828 free(mysql->options.my_cnf_file);
1829 free(mysql->options.my_cnf_group);
1830 free(mysql->options.charset_dir);
1831 free(mysql->options.charset_name);
1832 free(mysql->options.bind_address);
1833 free(mysql->options.ssl_key);
1834 free(mysql->options.ssl_cert);
1835 free(mysql->options.ssl_ca);
1836 free(mysql->options.ssl_capath);
1837 free(mysql->options.ssl_cipher);
1838
1839 if (mysql->options.extension)
1840 {
1841 struct mysql_async_context *ctxt;
1842 if ((ctxt = mysql->options.extension->async_context))
1843 {
1844 my_context_destroy(&ctxt->async_context);
1845 free(ctxt);
1846 mysql->options.extension->async_context= 0;
1847 }
1848 free(mysql->options.extension->plugin_dir);
1849 free(mysql->options.extension->default_auth);
1850 free(mysql->options.extension->db_driver);
1851 free(mysql->options.extension->ssl_crl);
1852 free(mysql->options.extension->ssl_crlpath);
1853 free(mysql->options.extension->tls_fp);
1854 free(mysql->options.extension->tls_fp_list);
1855 free(mysql->options.extension->tls_pw);
1856 free(mysql->options.extension->tls_version);
1857 free(mysql->options.extension->url);
1858 free(mysql->options.extension->connection_handler);
1859 if(hash_inited(&mysql->options.extension->connect_attrs))
1860 hash_free(&mysql->options.extension->connect_attrs);
1861 if (hash_inited(&mysql->options.extension->userdata))
1862 hash_free(&mysql->options.extension->userdata);
1863
1864 }
1865 free(mysql->options.extension);
1866 /* clear all pointer */
1867 memset(&mysql->options, 0, sizeof(mysql->options));
1868}
1869
1870static void mysql_close_memory(MYSQL *mysql)
1871{
1872 free(mysql->host_info);
1873 free(mysql->host);
1874 free(mysql->user);
1875 free(mysql->passwd);
1876 free(mysql->db);
1877 free(mysql->unix_socket);
1878 free(mysql->server_version);
1879 mysql->host_info= mysql->host= mysql->unix_socket=
1880 mysql->server_version=mysql->user=mysql->passwd=mysql->db=0;
1881}
1882
1883void my_set_error(MYSQL *mysql,
1884 unsigned int error_nr,
1885 const char *sqlstate,
1886 const char *format,
1887 ...)
1888{
1889 va_list ap;
1890
1891 mysql->net.last_errno= error_nr;
1892 ma_strmake(mysql->net.sqlstate, sqlstate, SQLSTATE_LENGTH);
1893 va_start(ap, format);
1894 vsnprintf(mysql->net.last_error, MYSQL_ERRMSG_SIZE,
1895 format ? format : ER(error_nr), ap);
1896 va_end(ap);
1897 return;
1898}
1899
1900void mysql_close_slow_part(MYSQL *mysql)
1901{
1902 if (mysql->net.pvio)
1903 {
1904 free_old_query(mysql);
1905 mysql->status=MYSQL_STATUS_READY; /* Force command */
1906 mysql->options.reconnect=0;
1907 if (mysql->net.pvio && mysql->net.buff)
1908 ma_simple_command(mysql, COM_QUIT,NullS,0,1,0);
1909 end_server(mysql);
1910 }
1911}
1912
1913void ma_clear_session_state(MYSQL *mysql)
1914{
1915 uint i;
1916
1917 if (!mysql || !mysql->extension)
1918 return;
1919
1920 for (i= SESSION_TRACK_BEGIN; i <= SESSION_TRACK_END; i++)
1921 {
1922 /* we acquired memory via ma_multi_alloc, so we don't need to free data */
1923 list_free(mysql->extension->session_state[i].list, 0);
1924 }
1925 memset(mysql->extension->session_state, 0, sizeof(struct st_mariadb_session_state) * SESSION_TRACK_TYPES);
1926}
1927
1928void STDCALL
1929mysql_close(MYSQL *mysql)
1930{
1931 if (mysql) /* Some simple safety */
1932 {
1933 if (mysql->extension && mysql->extension->conn_hdlr)
1934 {
1935 MA_CONNECTION_HANDLER *p= mysql->extension->conn_hdlr;
1936 if (p->plugin->close)
1937 p->plugin->close(mysql);
1938 free(p);
1939 /* Fix for CONC-294: Since we already called plugin->close function
1940 we need to prevent that mysql_close_slow_part (which sends COM_QUIT
1941 to the server) will be handled by plugin again. */
1942 mysql->extension->conn_hdlr= NULL;
1943 }
1944
1945 if (mysql->methods)
1946 mysql->methods->db_close(mysql);
1947
1948 /* reset the connection in all active statements */
1949 ma_invalidate_stmts(mysql, "mysql_close()");
1950
1951 mysql_close_memory(mysql);
1952 mysql_close_options(mysql);
1953 ma_clear_session_state(mysql);
1954
1955 if (mysql->net.extension)
1956 free(mysql->net.extension);
1957
1958 mysql->host_info=mysql->user=mysql->passwd=mysql->db=0;
1959
1960 /* Clear pointers for better safety */
1961 memset((char*) &mysql->options, 0, sizeof(mysql->options));
1962
1963 if (mysql->extension)
1964 free(mysql->extension);
1965
1966 mysql->net.pvio= 0;
1967 if (mysql->free_me)
1968 free(mysql);
1969 }
1970 return;
1971}
1972
1973
1974/**************************************************************************
1975** Do a query. If query returned rows, free old rows.
1976** Read data by mysql_store_result or by repeating calls to mysql_fetch_row
1977**************************************************************************/
1978
1979int STDCALL
1980mysql_query(MYSQL *mysql, const char *query)
1981{
1982 return mysql_real_query(mysql,query, (unsigned long) strlen(query));
1983}
1984
1985/*
1986 Send the query and return so we can do something else.
1987 Needs to be followed by mysql_read_query_result() when we want to
1988 finish processing it.
1989*/
1990
1991int STDCALL
1992mysql_send_query(MYSQL* mysql, const char* query, unsigned long length)
1993{
1994 return ma_simple_command(mysql, COM_QUERY, query, length, 1,0);
1995}
1996
1997int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length)
1998{
1999 size_t item_len;
2000 mysql->affected_rows= net_field_length_ll(&pos);
2001 mysql->insert_id= net_field_length_ll(&pos);
2002 mysql->server_status=uint2korr(pos);
2003 pos+=2;
2004 mysql->warning_count=uint2korr(pos);
2005 pos+=2;
2006 if (pos < mysql->net.read_pos+length)
2007 {
2008 if ((item_len= net_field_length(&pos)))
2009 mysql->info=(char*) pos;
2010
2011 /* check if server supports session tracking */
2012 if (mysql->server_capabilities & CLIENT_SESSION_TRACKING)
2013 {
2014 ma_clear_session_state(mysql);
2015 pos+= item_len;
2016
2017 if (mysql->server_status & SERVER_SESSION_STATE_CHANGED)
2018 {
2019 int i;
2020 if (pos < mysql->net.read_pos + length)
2021 {
2022 LIST *session_item;
2023 MYSQL_LEX_STRING *str= NULL;
2024 enum enum_session_state_type si_type;
2025 uchar *old_pos= pos;
2026 size_t item_len= net_field_length(&pos); /* length for all items */
2027
2028 /* length was already set, so make sure that info will be zero terminated */
2029 if (mysql->info)
2030 *old_pos= 0;
2031
2032 while (item_len > 0)
2033 {
2034 size_t plen;
2035 char *data;
2036 old_pos= pos;
2037 si_type= (enum enum_session_state_type)net_field_length(&pos);
2038 switch(si_type) {
2039 case SESSION_TRACK_SCHEMA:
2040 case SESSION_TRACK_STATE_CHANGE:
2041 case SESSION_TRACK_TRANSACTION_CHARACTERISTICS:
2042 case SESSION_TRACK_SYSTEM_VARIABLES:
2043 if (si_type != SESSION_TRACK_STATE_CHANGE)
2044 net_field_length(&pos); /* ignore total length, item length will follow next */
2045 plen= net_field_length(&pos);
2046 if (!ma_multi_malloc(0,
2047 &session_item, sizeof(LIST),
2048 &str, sizeof(MYSQL_LEX_STRING),
2049 &data, plen,
2050 NULL))
2051 {
2052 SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
2053 return -1;
2054 }
2055 str->length= plen;
2056 str->str= data;
2057 memcpy(str->str, (char *)pos, plen);
2058 pos+= plen;
2059 session_item->data= str;
2060 mysql->extension->session_state[si_type].list= list_add(mysql->extension->session_state[si_type].list, session_item);
2061
2062 /* in case schema has changed, we have to update mysql->db */
2063 if (si_type == SESSION_TRACK_SCHEMA)
2064 {
2065 free(mysql->db);
2066 mysql->db= malloc(plen + 1);
2067 memcpy(mysql->db, str->str, plen);
2068 mysql->db[plen]= 0;
2069 }
2070 else if (si_type == SESSION_TRACK_SYSTEM_VARIABLES)
2071 {
2072 my_bool set_charset= 0;
2073 /* make sure that we update charset in case it has changed */
2074 if (!strncmp(str->str, "character_set_client", str->length))
2075 set_charset= 1;
2076 plen= net_field_length(&pos);
2077 if (!ma_multi_malloc(0,
2078 &session_item, sizeof(LIST),
2079 &str, sizeof(MYSQL_LEX_STRING),
2080 &data, plen,
2081 NULL))
2082 {
2083 SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
2084 return -1;
2085 }
2086 str->length= plen;
2087 str->str= data;
2088 memcpy(str->str, (char *)pos, plen);
2089 pos+= plen;
2090 session_item->data= str;
2091 mysql->extension->session_state[si_type].list= list_add(mysql->extension->session_state[si_type].list, session_item);
2092 if (set_charset &&
2093 strncmp(mysql->charset->csname, str->str, str->length) != 0)
2094 {
2095 char cs_name[64];
2096 MARIADB_CHARSET_INFO *cs_info;
2097 memcpy(cs_name, str->str, str->length);
2098 cs_name[str->length]= 0;
2099 if ((cs_info = (MARIADB_CHARSET_INFO *)mysql_find_charset_name(cs_name)))
2100 mysql->charset= cs_info;
2101 }
2102 }
2103 break;
2104 default:
2105 /* not supported yet */
2106 plen= net_field_length(&pos);
2107 pos+= plen;
2108 break;
2109 }
2110 item_len-= (pos - old_pos);
2111 }
2112 }
2113 for (i= SESSION_TRACK_BEGIN; i <= SESSION_TRACK_END; i++)
2114 {
2115 mysql->extension->session_state[i].list= list_reverse(mysql->extension->session_state[i].list);
2116 mysql->extension->session_state[i].current= mysql->extension->session_state[i].list;
2117 }
2118 }
2119 }
2120 }
2121 /* CONC-351: clear session state information */
2122 else if (mysql->server_capabilities & CLIENT_SESSION_TRACKING)
2123 ma_clear_session_state(mysql);
2124 return(0);
2125}
2126
2127int mthd_my_read_query_result(MYSQL *mysql)
2128{
2129 uchar *pos;
2130 ulong field_count;
2131 MYSQL_DATA *fields;
2132 ulong length;
2133 my_bool can_local_infile= (mysql->options.extension) && (mysql->extension->auto_local_infile != WAIT_FOR_QUERY);
2134
2135 if (mysql->options.extension && mysql->extension->auto_local_infile == ACCEPT_FILE_REQUEST)
2136 mysql->extension->auto_local_infile= WAIT_FOR_QUERY;
2137
2138 if (!mysql || (length = ma_net_safe_read(mysql)) == packet_error)
2139 {
2140 return(1);
2141 }
2142 free_old_query(mysql); /* Free old result */
2143get_info:
2144 pos=(uchar*) mysql->net.read_pos;
2145 if ((field_count= net_field_length(&pos)) == 0)
2146 return ma_read_ok_packet(mysql, pos, length);
2147 if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
2148 {
2149 int error=mysql_handle_local_infile(mysql, (char *)pos, can_local_infile);
2150
2151 if ((length=ma_net_safe_read(mysql)) == packet_error || error)
2152 return(-1);
2153 goto get_info; /* Get info packet */
2154 }
2155 if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
2156 mysql->server_status|= SERVER_STATUS_IN_TRANS;
2157
2158 mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */
2159 if (!(fields=mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,8)))
2160 return(-1);
2161 if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,
2162 (uint) field_count,1,
2163 (my_bool) test(mysql->server_capabilities &
2164 CLIENT_LONG_FLAG))))
2165 return(-1);
2166 mysql->status=MYSQL_STATUS_GET_RESULT;
2167 mysql->field_count=field_count;
2168 return(0);
2169}
2170
2171int STDCALL mysql_session_track_get_next(MYSQL *mysql, enum enum_session_state_type type,
2172 const char **data, size_t *length)
2173{
2174 MYSQL_LEX_STRING *str;
2175 if (!mysql->extension->session_state[type].current)
2176 return 1;
2177
2178 str= (MYSQL_LEX_STRING *)mysql->extension->session_state[type].current->data;
2179 mysql->extension->session_state[type].current= mysql->extension->session_state[type].current->next;
2180
2181 *data= str->str ? str->str : NULL;
2182 *length= str->str ? str->length : 0;
2183 return 0;
2184}
2185
2186int STDCALL mysql_session_track_get_first(MYSQL *mysql, enum enum_session_state_type type,
2187 const char **data, size_t *length)
2188{
2189 mysql->extension->session_state[type].current= mysql->extension->session_state[type].list;
2190 return mysql_session_track_get_next(mysql, type, data, length);
2191}
2192
2193my_bool STDCALL
2194mysql_read_query_result(MYSQL *mysql)
2195{
2196 return test(mysql->methods->db_read_query_result(mysql)) ? 1 : 0;
2197}
2198
2199int STDCALL
2200mysql_real_query(MYSQL *mysql, const char *query, unsigned long length)
2201{
2202 my_bool skip_result= OPT_EXT_VAL(mysql, multi_command);
2203
2204 if (length == (unsigned long)-1)
2205 length= (unsigned long)strlen(query);
2206
2207 free_old_query(mysql);
2208
2209 if (ma_simple_command(mysql, COM_QUERY,query,length,1,0))
2210 return(-1);
2211 if (!skip_result)
2212 return(mysql->methods->db_read_query_result(mysql));
2213 return(0);
2214}
2215
2216/**************************************************************************
2217** Alloc result struct for buffered results. All rows are read to buffer.
2218** mysql_data_seek may be used.
2219**************************************************************************/
2220
2221MYSQL_RES * STDCALL
2222mysql_store_result(MYSQL *mysql)
2223{
2224 MYSQL_RES *result;
2225
2226 if (!mysql->fields)
2227 return(0);
2228 if (mysql->status != MYSQL_STATUS_GET_RESULT)
2229 {
2230 SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
2231 return(0);
2232 }
2233 mysql->status=MYSQL_STATUS_READY; /* server is ready */
2234 if (!(result=(MYSQL_RES*) calloc(1, sizeof(MYSQL_RES)+
2235 sizeof(ulong)*mysql->field_count)))
2236 {
2237 SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
2238 return(0);
2239 }
2240 result->eof=1; /* Marker for buffered */
2241 result->lengths=(ulong*) (result+1);
2242 if (!(result->data=mysql->methods->db_read_rows(mysql,mysql->fields,mysql->field_count)))
2243 {
2244 free(result);
2245 return(0);
2246 }
2247 mysql->affected_rows= result->row_count= result->data->rows;
2248 result->data_cursor= result->data->data;
2249 result->fields= mysql->fields;
2250 result->field_alloc= mysql->field_alloc;
2251 result->field_count= mysql->field_count;
2252 result->current_field=0;
2253 result->current_row=0; /* Must do a fetch first */
2254 mysql->fields=0; /* fields is now in result */
2255 return(result); /* Data fetched */
2256}
2257
2258
2259/**************************************************************************
2260** Alloc struct for use with unbuffered reads. Data is fetched by domand
2261** when calling to mysql_fetch_row.
2262** mysql_data_seek is a noop.
2263**
2264** No other queries may be specified with the same MYSQL handle.
2265** There shouldn't be much processing per row because mysql server shouldn't
2266** have to wait for the client (and will not wait more than 30 sec/packet).
2267**************************************************************************/
2268
2269MYSQL_RES * STDCALL
2270mysql_use_result(MYSQL *mysql)
2271{
2272 MYSQL_RES *result;
2273
2274 if (!mysql->fields)
2275 return(0);
2276 if (mysql->status != MYSQL_STATUS_GET_RESULT)
2277 {
2278 SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
2279 return(0);
2280 }
2281 if (!(result=(MYSQL_RES*) calloc(1, sizeof(*result)+
2282 sizeof(ulong)*mysql->field_count)))
2283 return(0);
2284 result->lengths=(ulong*) (result+1);
2285 if (!(result->row=(MYSQL_ROW)
2286 malloc(sizeof(result->row[0])*(mysql->field_count+1))))
2287 { /* Ptrs: to one row */
2288 free(result);
2289 return(0);
2290 }
2291 result->fields= mysql->fields;
2292 result->field_alloc= mysql->field_alloc;
2293 result->field_count= mysql->field_count;
2294 result->current_field=0;
2295 result->handle= mysql;
2296 result->current_row= 0;
2297 mysql->fields=0; /* fields is now in result */
2298 mysql->status=MYSQL_STATUS_USE_RESULT;
2299 return(result); /* Data is read to be fetched */
2300}
2301
2302/**************************************************************************
2303** Return next field of the query results
2304**************************************************************************/
2305MYSQL_FIELD * STDCALL
2306mysql_fetch_field(MYSQL_RES *result)
2307{
2308 if (result->current_field >= result->field_count)
2309 return(NULL);
2310 return &result->fields[result->current_field++];
2311}
2312
2313/**************************************************************************
2314** Return next row of the query results
2315**************************************************************************/
2316MYSQL_ROW STDCALL
2317mysql_fetch_row(MYSQL_RES *res)
2318{
2319 if (!res)
2320 return 0;
2321 if (res->handle)
2322 {
2323 if (res->handle->status != MYSQL_STATUS_USE_RESULT &&
2324 res->handle->status != MYSQL_STATUS_GET_RESULT)
2325 return 0;
2326 }
2327 if (!res->data)
2328 { /* Unbufferred fetch */
2329 if (!res->eof && res->handle)
2330 {
2331 if (!(res->handle->methods->db_read_one_row(res->handle,res->field_count,res->row, res->lengths)))
2332 {
2333 res->row_count++;
2334 return(res->current_row=res->row);
2335 }
2336 res->eof=1;
2337 res->handle->status=MYSQL_STATUS_READY;
2338 /* Don't clear handle in mysql_free_results */
2339 res->handle=0;
2340 }
2341 return((MYSQL_ROW) NULL);
2342 }
2343 {
2344 MYSQL_ROW tmp;
2345 if (!res->data_cursor)
2346 {
2347 return(res->current_row=(MYSQL_ROW) NULL);
2348 }
2349 tmp = res->data_cursor->data;
2350 res->data_cursor = res->data_cursor->next;
2351 return(res->current_row=tmp);
2352 }
2353}
2354
2355/**************************************************************************
2356** Get column lengths of the current row
2357** If one uses mysql_use_result, res->lengths contains the length information,
2358** else the lengths are calculated from the offset between pointers.
2359**************************************************************************/
2360
2361ulong * STDCALL
2362mysql_fetch_lengths(MYSQL_RES *res)
2363{
2364 ulong *lengths,*prev_length;
2365 char *start;
2366 MYSQL_ROW column,end;
2367
2368 if (!(column=res->current_row))
2369 return 0; /* Something is wrong */
2370 if (res->data)
2371 {
2372 start=0;
2373 prev_length=0; /* Keep gcc happy */
2374 lengths=res->lengths;
2375 for (end=column+res->field_count+1 ; column != end ; column++,lengths++)
2376 {
2377 if (!*column)
2378 {
2379 *lengths=0; /* Null */
2380 continue;
2381 }
2382 if (start) /* Found end of prev string */
2383 *prev_length= (uint) (*column-start-1);
2384 start= *column;
2385 prev_length=lengths;
2386 }
2387 }
2388 return res->lengths;
2389}
2390
2391/**************************************************************************
2392** Move to a specific row and column
2393**************************************************************************/
2394
2395void STDCALL
2396mysql_data_seek(MYSQL_RES *result, unsigned long long row)
2397{
2398 MYSQL_ROWS *tmp=0;
2399 if (result->data)
2400 for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ;
2401 result->current_row=0;
2402 result->data_cursor = tmp;
2403}
2404
2405/*************************************************************************
2406** put the row or field cursor one a position one got from mysql_row_tell()
2407** This doesn't restore any data. The next mysql_fetch_row or
2408** mysql_fetch_field will return the next row or field after the last used
2409*************************************************************************/
2410
2411MYSQL_ROW_OFFSET STDCALL
2412mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET row)
2413{
2414 MYSQL_ROW_OFFSET return_value=result->data_cursor;
2415 result->current_row= 0;
2416 result->data_cursor= row;
2417 return return_value;
2418}
2419
2420
2421MYSQL_FIELD_OFFSET STDCALL
2422mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET field_offset)
2423{
2424 MYSQL_FIELD_OFFSET return_value=result->current_field;
2425 result->current_field=field_offset;
2426 return return_value;
2427}
2428
2429/*****************************************************************************
2430** List all databases
2431*****************************************************************************/
2432
2433MYSQL_RES * STDCALL
2434mysql_list_dbs(MYSQL *mysql, const char *wild)
2435{
2436 char buff[255];
2437 snprintf(buff, 255, "SHOW DATABASES LIKE '%s'", wild ? wild : "%");
2438 if (mysql_query(mysql,buff))
2439 return(0);
2440 return (mysql_store_result(mysql));
2441}
2442
2443
2444/*****************************************************************************
2445** List all tables in a database
2446** If wild is given then only the tables matching wild are returned
2447*****************************************************************************/
2448
2449MYSQL_RES * STDCALL
2450mysql_list_tables(MYSQL *mysql, const char *wild)
2451{
2452 char buff[255];
2453
2454 snprintf(buff, 255, "SHOW TABLES LIKE '%s'", wild ? wild : "%");
2455 if (mysql_query(mysql,buff))
2456 return(0);
2457 return (mysql_store_result(mysql));
2458}
2459
2460
2461/**************************************************************************
2462** List all fields in a table
2463** If wild is given then only the fields matching wild are returned
2464** Instead of this use query:
2465** show fields in 'table' like "wild"
2466**************************************************************************/
2467
2468MYSQL_RES * STDCALL
2469mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)
2470{
2471 MYSQL_RES *result;
2472 MYSQL_DATA *query;
2473 char buff[255];
2474 int length= 0;
2475
2476 LINT_INIT(query);
2477
2478 length= snprintf(buff, 128, "%s%c%s", table, '\0', wild ? wild : "");
2479
2480 if (ma_simple_command(mysql, COM_FIELD_LIST,buff,length,1,0) ||
2481 !(query = mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,8)))
2482 return(NULL);
2483
2484 free_old_query(mysql);
2485 if (!(result = (MYSQL_RES *) calloc(1, sizeof(MYSQL_RES))))
2486 {
2487 free_rows(query);
2488 return(NULL);
2489 }
2490 result->field_alloc=mysql->field_alloc;
2491 mysql->fields=0;
2492 result->eof=1;
2493 result->field_count = (uint) query->rows;
2494 result->fields= unpack_fields(query,&result->field_alloc,
2495 result->field_count,1,
2496 (my_bool) test(mysql->server_capabilities &
2497 CLIENT_LONG_FLAG));
2498 if (result->fields)
2499 return(result);
2500
2501 free(result);
2502 return(NULL);
2503}
2504
2505/* List all running processes (threads) in server */
2506
2507MYSQL_RES * STDCALL
2508mysql_list_processes(MYSQL *mysql)
2509{
2510 MYSQL_DATA *fields;
2511 uint field_count;
2512 uchar *pos;
2513
2514 LINT_INIT(fields);
2515 if (ma_simple_command(mysql, COM_PROCESS_INFO,0,0,0,0))
2516 return(NULL);
2517 free_old_query(mysql);
2518 pos=(uchar*) mysql->net.read_pos;
2519 field_count=(uint) net_field_length(&pos);
2520 if (!(fields = mysql->methods->db_read_rows(mysql,(MYSQL_FIELD*) 0,5)))
2521 return(NULL);
2522 if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,field_count,0,
2523 (my_bool) test(mysql->server_capabilities &
2524 CLIENT_LONG_FLAG))))
2525 return(NULL);
2526 mysql->status=MYSQL_STATUS_GET_RESULT;
2527 mysql->field_count=field_count;
2528 return(mysql_store_result(mysql));
2529}
2530
2531/* In 5.0 this version became an additional parameter shutdown_level */
2532int STDCALL
2533mysql_shutdown(MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level)
2534{
2535 uchar s_level[2];
2536 s_level[0]= (uchar)shutdown_level;
2537 return(ma_simple_command(mysql, COM_SHUTDOWN, (char *)s_level, 1, 0, 0));
2538}
2539
2540int STDCALL
2541mysql_refresh(MYSQL *mysql,uint options)
2542{
2543 uchar bits[1];
2544 bits[0]= (uchar) options;
2545 return(ma_simple_command(mysql, COM_REFRESH,(char*) bits,1,0,0));
2546}
2547
2548int STDCALL
2549mysql_kill(MYSQL *mysql,ulong pid)
2550{
2551 char buff[12];
2552 int4store(buff,pid);
2553 /* if we kill our own thread, reading the response packet will fail */
2554 return(ma_simple_command(mysql, COM_PROCESS_KILL,buff,4,0,0));
2555}
2556
2557
2558int STDCALL
2559mysql_dump_debug_info(MYSQL *mysql)
2560{
2561 return(ma_simple_command(mysql, COM_DEBUG,0,0,0,0));
2562}
2563
2564char * STDCALL
2565mysql_stat(MYSQL *mysql)
2566{
2567 if (ma_simple_command(mysql, COM_STATISTICS,0,0,0,0))
2568 return mysql->net.last_error;
2569 mysql->net.read_pos[mysql->packet_length]=0; /* End of stat string */
2570 if (!mysql->net.read_pos[0])
2571 {
2572 SET_CLIENT_ERROR(mysql, CR_WRONG_HOST_INFO , SQLSTATE_UNKNOWN, 0);
2573 return mysql->net.last_error;
2574 }
2575 return((char*) mysql->net.read_pos);
2576}
2577
2578int STDCALL
2579mysql_ping(MYSQL *mysql)
2580{
2581 int rc;
2582 rc= ma_simple_command(mysql, COM_PING, 0, 0, 0, 0);
2583 if (rc && mysql->options.reconnect)
2584 rc= ma_simple_command(mysql, COM_PING, 0, 0, 0, 0);
2585 return rc;
2586}
2587
2588char * STDCALL
2589mysql_get_server_info(MYSQL *mysql)
2590{
2591 return((char*) mysql->server_version);
2592}
2593
2594static size_t mariadb_server_version_id(MYSQL *mysql)
2595{
2596 size_t major, minor, patch;
2597 char *p;
2598
2599 if (!(p = mysql->server_version)) {
2600 return 0;
2601 }
2602
2603 major = strtol(p, &p, 10);
2604 p += 1; /* consume the dot */
2605 minor = strtol(p, &p, 10);
2606 p += 1; /* consume the dot */
2607 patch = strtol(p, &p, 10);
2608
2609 return (major * 10000L + (unsigned long)(minor * 100L + patch));
2610}
2611
2612unsigned long STDCALL mysql_get_server_version(MYSQL *mysql)
2613{
2614 return (unsigned long)mariadb_server_version_id(mysql);
2615}
2616
2617char * STDCALL
2618mysql_get_host_info(MYSQL *mysql)
2619{
2620 return(mysql->host_info);
2621}
2622
2623uint STDCALL
2624mysql_get_proto_info(MYSQL *mysql)
2625{
2626 return (mysql->protocol_version);
2627}
2628
2629const char * STDCALL
2630mysql_get_client_info(void)
2631{
2632 return (char*) MARIADB_CLIENT_VERSION_STR;
2633}
2634
2635static size_t get_store_length(size_t length)
2636{
2637 #define MAX_STORE_SIZE 9
2638 unsigned char buffer[MAX_STORE_SIZE], *p;
2639
2640 /* We just store the length and substract offset of our buffer
2641 to determine the length */
2642 p= mysql_net_store_length(buffer, length);
2643 return p - buffer;
2644}
2645
2646uchar *ma_get_hash_keyval(const uchar *hash_entry,
2647 unsigned int *length,
2648 my_bool not_used __attribute__((unused)))
2649{
2650 /* Hash entry has the following format:
2651 Offset: 0 key (\0 terminated)
2652 key_length + 1 value (\0 terminated)
2653 */
2654 uchar *p= (uchar *)hash_entry;
2655 size_t len= strlen((char *)p);
2656 *length= (unsigned int)len;
2657 return p;
2658}
2659
2660void ma_int_hash_free(void *p)
2661{
2662 free(p);
2663}
2664
2665int
2666mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...)
2667{
2668 va_list ap;
2669 void *arg1;
2670 size_t stacksize;
2671 struct mysql_async_context *ctxt;
2672
2673 va_start(ap, option);
2674
2675 arg1= va_arg(ap, void *);
2676
2677 switch (option) {
2678 case MYSQL_OPT_CONNECT_TIMEOUT:
2679 mysql->options.connect_timeout= *(uint*) arg1;
2680 break;
2681 case MYSQL_OPT_COMPRESS:
2682 mysql->options.compress= 1; /* Remember for connect */
2683 mysql->options.client_flag|= CLIENT_COMPRESS;
2684 break;
2685 case MYSQL_OPT_NAMED_PIPE:
2686 mysql->options.named_pipe=1; /* Force named pipe */
2687 break;
2688 case MYSQL_OPT_LOCAL_INFILE: /* Allow LOAD DATA LOCAL ?*/
2689 if (!arg1 || test(*(unsigned int*) arg1))
2690 mysql->options.client_flag|= CLIENT_LOCAL_FILES;
2691 else
2692 mysql->options.client_flag&= ~CLIENT_LOCAL_FILES;
2693 if (arg1) {
2694 CHECK_OPT_EXTENSION_SET(&mysql->options);
2695 mysql->extension->auto_local_infile= *(uint*)arg1 == LOCAL_INFILE_MODE_AUTO
2696 ? WAIT_FOR_QUERY : ALWAYS_ACCEPT;
2697 }
2698 break;
2699 case MYSQL_INIT_COMMAND:
2700 options_add_initcommand(&mysql->options, (char *)arg1);
2701 break;
2702 case MYSQL_READ_DEFAULT_FILE:
2703 OPT_SET_VALUE_STR(&mysql->options, my_cnf_file, (char *)arg1);
2704 break;
2705 case MYSQL_READ_DEFAULT_GROUP:
2706 OPT_SET_VALUE_STR(&mysql->options, my_cnf_group, arg1 ? (char *)arg1 : "");
2707 break;
2708 case MYSQL_SET_CHARSET_DIR:
2709 OPT_SET_VALUE_STR(&mysql->options, charset_dir, arg1);
2710 break;
2711 case MYSQL_SET_CHARSET_NAME:
2712 OPT_SET_VALUE_STR(&mysql->options, charset_name, arg1);
2713 break;
2714 case MYSQL_OPT_RECONNECT:
2715 mysql->options.reconnect= *(my_bool *)arg1;
2716 break;
2717 case MYSQL_OPT_PROTOCOL:
2718 mysql->options.protocol= *((uint *)arg1);
2719 break;
2720#ifdef _WIN32
2721 case MYSQL_SHARED_MEMORY_BASE_NAME:
2722 OPT_SET_VALUE_STR(&mysql->options, shared_memory_base_name, arg1);
2723 break;
2724#endif
2725 case MYSQL_OPT_READ_TIMEOUT:
2726 mysql->options.read_timeout= *(uint *)arg1;
2727 break;
2728 case MYSQL_OPT_WRITE_TIMEOUT:
2729 mysql->options.write_timeout= *(uint *)arg1;
2730 break;
2731 case MYSQL_REPORT_DATA_TRUNCATION:
2732 mysql->options.report_data_truncation= *(my_bool *)arg1;
2733 break;
2734 case MYSQL_PROGRESS_CALLBACK:
2735 CHECK_OPT_EXTENSION_SET(&mysql->options);
2736 if (mysql->options.extension)
2737 mysql->options.extension->report_progress=
2738 (void (*)(const MYSQL *, uint, uint, double, const char *, uint)) arg1;
2739 break;
2740 case MYSQL_SERVER_PUBLIC_KEY:
2741 OPT_SET_EXTENDED_VALUE_STR(&mysql->options, server_public_key, (char *)arg1);
2742 break;
2743 case MYSQL_PLUGIN_DIR:
2744 OPT_SET_EXTENDED_VALUE_STR(&mysql->options, plugin_dir, (char *)arg1);
2745 break;
2746 case MYSQL_DEFAULT_AUTH:
2747 OPT_SET_EXTENDED_VALUE_STR(&mysql->options, default_auth, (char *)arg1);
2748 break;
2749 case MYSQL_OPT_NONBLOCK:
2750 if (mysql->options.extension &&
2751 (ctxt = mysql->options.extension->async_context) != 0)
2752 {
2753 /*
2754 We must not allow changing the stack size while a non-blocking call is
2755 suspended (as the stack is then in use).
2756 */
2757 if (ctxt->suspended)
2758 goto end;
2759 my_context_destroy(&ctxt->async_context);
2760 free(ctxt);
2761 }
2762 if (!(ctxt= (struct mysql_async_context *)
2763 calloc(1, sizeof(*ctxt))))
2764 {
2765 SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
2766 goto end;
2767 }
2768 stacksize= 0;
2769 if (arg1)
2770 stacksize= *(const size_t *)arg1;
2771 if (!stacksize)
2772 stacksize= ASYNC_CONTEXT_DEFAULT_STACK_SIZE;
2773 if (my_context_init(&ctxt->async_context, stacksize))
2774 {
2775 free(ctxt);
2776 goto end;
2777 }
2778 if (!mysql->options.extension)
2779 if(!(mysql->options.extension= (struct st_mysql_options_extension *)
2780 calloc(1, sizeof(struct st_mysql_options_extension))))
2781 {
2782 free(ctxt);
2783 SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
2784 goto end;
2785 }
2786 mysql->options.extension->async_context= ctxt;
2787 break;
2788 case MYSQL_OPT_MAX_ALLOWED_PACKET:
2789 if (mysql)
2790 mysql->options.max_allowed_packet= (unsigned long)(*(size_t *)arg1);
2791 else
2792 max_allowed_packet= (unsigned long)(*(size_t *)arg1);
2793 break;
2794 case MYSQL_OPT_NET_BUFFER_LENGTH:
2795 net_buffer_length= (unsigned long)(*(size_t *)arg1);
2796 break;
2797 case MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS:
2798 if (*(my_bool *)arg1)
2799 mysql->options.client_flag |= CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS;
2800 else
2801 mysql->options.client_flag &= ~CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS;
2802 break;
2803 case MYSQL_OPT_SSL_ENFORCE:
2804 mysql->options.use_ssl= (*(my_bool *)arg1);
2805 break;
2806 case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
2807 if (*(my_bool *)arg1)
2808 mysql->options.client_flag |= CLIENT_SSL_VERIFY_SERVER_CERT;
2809 else
2810 mysql->options.client_flag &= ~CLIENT_SSL_VERIFY_SERVER_CERT;
2811 break;
2812 case MYSQL_OPT_SSL_KEY:
2813 OPT_SET_VALUE_STR(&mysql->options, ssl_key, (char *)arg1);
2814 break;
2815 case MYSQL_OPT_SSL_CERT:
2816 OPT_SET_VALUE_STR(&mysql->options, ssl_cert, (char *)arg1);
2817 break;
2818 case MYSQL_OPT_SSL_CA:
2819 OPT_SET_VALUE_STR(&mysql->options, ssl_ca, (char *)arg1);
2820 break;
2821 case MYSQL_OPT_SSL_CAPATH:
2822 OPT_SET_VALUE_STR(&mysql->options, ssl_capath, (char *)arg1);
2823 break;
2824 case MYSQL_OPT_SSL_CIPHER:
2825 OPT_SET_VALUE_STR(&mysql->options, ssl_cipher, (char *)arg1);
2826 break;
2827 case MYSQL_OPT_SSL_CRL:
2828 OPT_SET_EXTENDED_VALUE_STR(&mysql->options, ssl_crl, (char *)arg1);
2829 break;
2830 case MYSQL_OPT_SSL_CRLPATH:
2831 OPT_SET_EXTENDED_VALUE_STR(&mysql->options, ssl_crlpath, (char *)arg1);
2832 break;
2833 case MYSQL_OPT_CONNECT_ATTR_DELETE:
2834 {
2835 uchar *h;
2836 CHECK_OPT_EXTENSION_SET(&mysql->options);
2837 if (hash_inited(&mysql->options.extension->connect_attrs) &&
2838 (h= (uchar *)hash_search(&mysql->options.extension->connect_attrs, (uchar *)arg1,
2839 arg1 ? (uint)strlen((char *)arg1) : 0)))
2840 {
2841 uchar *p= h;
2842 size_t key_len= strlen((char *)p);
2843 mysql->options.extension->connect_attrs_len-= key_len + get_store_length(key_len);
2844 p+= key_len + 1;
2845 key_len= strlen((char *)p);
2846 mysql->options.extension->connect_attrs_len-= key_len + get_store_length(key_len);
2847 hash_delete(&mysql->options.extension->connect_attrs, h);
2848 }
2849
2850 }
2851 break;
2852 case MYSQL_OPT_CONNECT_ATTR_RESET:
2853 CHECK_OPT_EXTENSION_SET(&mysql->options);
2854 if (hash_inited(&mysql->options.extension->connect_attrs))
2855 {
2856 hash_free(&mysql->options.extension->connect_attrs);
2857 mysql->options.extension->connect_attrs_len= 0;
2858 }
2859 break;
2860 case MARIADB_OPT_CONNECTION_HANDLER:
2861 OPT_SET_EXTENDED_VALUE_STR(&mysql->options, connection_handler, (char *)arg1);
2862 break;
2863 case MARIADB_OPT_PORT:
2864 OPT_SET_VALUE_INT(&mysql->options, port, *((uint *)arg1));
2865 break;
2866 case MARIADB_OPT_UNIXSOCKET:
2867 OPT_SET_VALUE_STR(&mysql->options, unix_socket, arg1);
2868 break;
2869 case MARIADB_OPT_USER:
2870 OPT_SET_VALUE_STR(&mysql->options, user, arg1);
2871 break;
2872 case MARIADB_OPT_HOST:
2873 OPT_SET_VALUE_STR(&mysql->options, host, arg1);
2874 break;
2875 case MARIADB_OPT_SCHEMA:
2876 OPT_SET_VALUE_STR(&mysql->options, db, arg1);
2877 break;
2878 case MARIADB_OPT_DEBUG:
2879 break;
2880 case MARIADB_OPT_FOUND_ROWS:
2881 mysql->options.client_flag|= CLIENT_FOUND_ROWS;
2882 break;
2883 case MARIADB_OPT_INTERACTIVE:
2884 mysql->options.client_flag|= CLIENT_INTERACTIVE;
2885 break;
2886 case MARIADB_OPT_MULTI_RESULTS:
2887 mysql->options.client_flag|= CLIENT_MULTI_RESULTS;
2888 break;
2889 case MARIADB_OPT_MULTI_STATEMENTS:
2890 mysql->options.client_flag|= CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS;
2891 break;
2892 case MARIADB_OPT_PASSWORD:
2893 OPT_SET_VALUE_STR(&mysql->options, password, arg1);
2894 break;
2895 case MARIADB_OPT_USERDATA:
2896 {
2897 void *data= va_arg(ap, void *);
2898 uchar *buffer, *p;
2899 char *key= (char *)arg1;
2900
2901 if (!key || !data)
2902 {
2903 SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0);
2904 goto end;
2905 }
2906
2907 CHECK_OPT_EXTENSION_SET(&mysql->options);
2908 if (!hash_inited(&mysql->options.extension->userdata))
2909 {
2910 if (_hash_init(&mysql->options.extension->userdata,
2911 0, 0, 0, ma_get_hash_keyval, ma_int_hash_free, 0))
2912 {
2913 SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
2914 goto end;
2915 }
2916 }
2917 /* check if key is already in buffer */
2918 p= (uchar *)hash_search(&mysql->options.extension->userdata,
2919 (uchar *)key,
2920 (uint)strlen(key));
2921 if (p)
2922 {
2923 p+= strlen(key) + 1;
2924 memcpy(p, &data, sizeof(void *));
2925 break;
2926 }
2927
2928 if (!(buffer= (uchar *)malloc(strlen(key) + 1 + sizeof(void *))))
2929 {
2930 SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
2931 goto end;
2932 }
2933
2934 p= buffer;
2935 strcpy((char *)p, key);
2936 p+= strlen(key) + 1;
2937 memcpy(p, &data, sizeof(void *));
2938
2939 if (hash_insert(&mysql->options.extension->userdata, buffer))
2940 {
2941 free(buffer);
2942 SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0);
2943 goto end;
2944 }
2945 }
2946 break;
2947 case MYSQL_OPT_CONNECT_ATTR_ADD:
2948 {
2949 uchar *buffer;
2950 void *arg2= va_arg(ap, void *);
2951 size_t storage_len, key_len= arg1 ? strlen((char *)arg1) : 0,
2952 value_len= arg2 ? strlen((char *)arg2) : 0;
2953 if (!key_len || !value_len)
2954 {
2955 SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0);
2956 goto end;
2957 }
2958 storage_len= key_len + value_len +
2959 get_store_length(key_len) +
2960 get_store_length(value_len);
2961
2962 /* since we store terminating zero character in hash, we need
2963 * to increase lengths */
2964 key_len++;
2965 value_len++;
2966
2967 CHECK_OPT_EXTENSION_SET(&mysql->options);
2968 if (!key_len ||
2969 storage_len + mysql->options.extension->connect_attrs_len > 0xFFFF)
2970 {
2971 SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0);
2972 goto end;
2973 }
2974
2975 if (!hash_inited(&mysql->options.extension->connect_attrs))
2976 {
2977 if (_hash_init(&mysql->options.extension->connect_attrs,
2978 0, 0, 0, ma_get_hash_keyval, ma_int_hash_free, 0))
2979 {
2980 SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
2981 goto end;
2982 }
2983 }
2984 if ((buffer= (uchar *)malloc(key_len + value_len)))
2985 {
2986 uchar *p= buffer;
2987 strcpy((char *)p, arg1);
2988 p+= (strlen(arg1) + 1);
2989 if (arg2)
2990 strcpy((char *)p, arg2);
2991
2992 if (hash_insert(&mysql->options.extension->connect_attrs, buffer))
2993 {
2994 free(buffer);
2995 SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, SQLSTATE_UNKNOWN, 0);
2996 goto end;
2997 }
2998 mysql->options.extension->connect_attrs_len+= storage_len;
2999 }
3000 else
3001 {
3002 SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
3003 goto end;
3004 }
3005 }
3006 break;
3007 case MYSQL_ENABLE_CLEARTEXT_PLUGIN:
3008 break;
3009 case MYSQL_SECURE_AUTH:
3010 mysql->options.secure_auth= *(my_bool *)arg1;
3011 break;
3012 case MYSQL_OPT_BIND:
3013 OPT_SET_VALUE_STR(&mysql->options, bind_address, arg1);
3014 break;
3015 case MARIADB_OPT_TLS_CIPHER_STRENGTH:
3016 OPT_SET_EXTENDED_VALUE_INT(&mysql->options, tls_cipher_strength, *((unsigned int *)arg1));
3017 break;
3018 case MARIADB_OPT_SSL_FP:
3019 case MARIADB_OPT_TLS_PEER_FP:
3020 OPT_SET_EXTENDED_VALUE_STR(&mysql->options, tls_fp, (char *)arg1);
3021 mysql->options.use_ssl= 1;
3022 break;
3023 case MARIADB_OPT_SSL_FP_LIST:
3024 case MARIADB_OPT_TLS_PEER_FP_LIST:
3025 OPT_SET_EXTENDED_VALUE_STR(&mysql->options, tls_fp_list, (char *)arg1);
3026 mysql->options.use_ssl= 1;
3027 break;
3028 case MARIADB_OPT_TLS_PASSPHRASE:
3029 OPT_SET_EXTENDED_VALUE_STR(&mysql->options, tls_pw, (char *)arg1);
3030 break;
3031 case MARIADB_OPT_CONNECTION_READ_ONLY:
3032 OPT_SET_EXTENDED_VALUE_INT(&mysql->options, read_only, *(my_bool *)arg1);
3033 break;
3034 case MARIADB_OPT_PROXY_HEADER:
3035 {
3036 size_t arg2 = va_arg(ap, size_t);
3037 OPT_SET_EXTENDED_VALUE(&mysql->options, proxy_header, (char *)arg1);
3038 OPT_SET_EXTENDED_VALUE(&mysql->options, proxy_header_len, arg2);
3039 }
3040 break;
3041 case MARIADB_OPT_TLS_VERSION:
3042 case MYSQL_OPT_TLS_VERSION:
3043 OPT_SET_EXTENDED_VALUE_STR(&mysql->options, tls_version, (char *)arg1);
3044 break;
3045 case MARIADB_OPT_IO_WAIT:
3046 CHECK_OPT_EXTENSION_SET(&mysql->options);
3047 mysql->options.extension->io_wait = (int(*)(my_socket, my_bool, int))arg1;
3048 break;
3049 default:
3050 va_end(ap);
3051 SET_CLIENT_ERROR(mysql, CR_NOT_IMPLEMENTED, SQLSTATE_UNKNOWN, 0);
3052 return(1);
3053 }
3054 va_end(ap);
3055 return(0);
3056end:
3057 va_end(ap);
3058 return(1);
3059}
3060
3061int
3062mysql_get_optionv(MYSQL *mysql, enum mysql_option option, void *arg, ...)
3063{
3064 va_list ap;
3065
3066 va_start(ap, arg);
3067
3068 switch(option) {
3069 case MYSQL_OPT_CONNECT_TIMEOUT:
3070 *((uint *)arg)= mysql->options.connect_timeout;
3071 break;
3072 case MYSQL_OPT_COMPRESS:
3073 *((my_bool *)arg)= mysql->options.compress;
3074 break;
3075 case MYSQL_OPT_NAMED_PIPE:
3076 *((my_bool *)arg)= mysql->options.named_pipe;
3077 break;
3078 case MYSQL_OPT_LOCAL_INFILE: /* Allow LOAD DATA LOCAL ?*/
3079 *((uint *)arg)= test(mysql->options.client_flag & CLIENT_LOCAL_FILES);
3080 break;
3081 case MYSQL_INIT_COMMAND:
3082 /* mysql_get_optionsv(mysql, MYSQL_INIT_COMMAND, commands, elements) */
3083 {
3084 unsigned int *elements;
3085 if (arg)
3086 *((char **)arg)= mysql->options.init_command ? mysql->options.init_command->buffer : NULL;
3087 if ((elements= va_arg(ap, unsigned int *)))
3088 *elements= mysql->options.init_command ? mysql->options.init_command->elements : 0;
3089 }
3090 break;
3091 case MYSQL_READ_DEFAULT_FILE:
3092 *((char **)arg)= mysql->options.my_cnf_file;
3093 break;
3094 case MYSQL_READ_DEFAULT_GROUP:
3095 *((char **)arg)= mysql->options.my_cnf_group;
3096 break;
3097 case MYSQL_SET_CHARSET_DIR:
3098 /* not supported in this version. Since all character sets
3099 are internally available, we don't throw an error */
3100 *((char **)arg)= NULL;
3101 break;
3102 case MYSQL_SET_CHARSET_NAME:
3103 if (mysql->charset)
3104 *((const char **)arg)= mysql->charset->csname;
3105 else
3106 *((char **)arg)= mysql->options.charset_name;
3107 break;
3108 case MYSQL_OPT_RECONNECT:
3109 *((my_bool *)arg)= mysql->options.reconnect;
3110 break;
3111 case MYSQL_OPT_PROTOCOL:
3112 *((uint *)arg)= mysql->options.protocol;
3113 break;
3114 case MYSQL_OPT_READ_TIMEOUT:
3115 *((uint *)arg)= mysql->options.read_timeout;
3116 break;
3117 case MYSQL_OPT_WRITE_TIMEOUT:
3118 *((uint *)arg)= mysql->options.write_timeout;
3119 break;
3120 case MYSQL_REPORT_DATA_TRUNCATION:
3121 *((my_bool *)arg)= mysql->options.report_data_truncation;
3122 break;
3123 case MYSQL_PROGRESS_CALLBACK:
3124 *((void (**)(const MYSQL *, uint, uint, double, const char *, uint))arg)=
3125 mysql->options.extension ? mysql->options.extension->report_progress : NULL;
3126 break;
3127 case MYSQL_SERVER_PUBLIC_KEY:
3128 *((char **)arg)= mysql->options.extension ?
3129 mysql->options.extension->server_public_key : NULL;
3130 break;
3131 case MYSQL_PLUGIN_DIR:
3132 *((char **)arg)= mysql->options.extension ? mysql->options.extension->plugin_dir : NULL;
3133 break;
3134 case MYSQL_DEFAULT_AUTH:
3135 *((char **)arg)= mysql->options.extension ? mysql->options.extension->default_auth : NULL;
3136 break;
3137 case MYSQL_OPT_NONBLOCK:
3138 *((my_bool *)arg)= test(mysql->options.extension && mysql->options.extension->async_context);
3139 break;
3140 case MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS:
3141 *((my_bool *)arg)= test(mysql->options.client_flag & CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS);
3142 break;
3143 case MYSQL_OPT_SSL_ENFORCE:
3144 *((my_bool *)arg)= mysql->options.use_ssl;
3145 break;
3146 case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
3147 *((my_bool *)arg)= test(mysql->options.client_flag & CLIENT_SSL_VERIFY_SERVER_CERT);
3148 break;
3149 case MYSQL_OPT_SSL_KEY:
3150 *((char **)arg)= mysql->options.ssl_key;
3151 break;
3152 case MYSQL_OPT_SSL_CERT:
3153 *((char **)arg)= mysql->options.ssl_cert;
3154 break;
3155 case MYSQL_OPT_SSL_CA:
3156 *((char **)arg)= mysql->options.ssl_ca;
3157 break;
3158 case MYSQL_OPT_SSL_CAPATH:
3159 *((char **)arg)= mysql->options.ssl_capath;
3160 break;
3161 case MYSQL_OPT_SSL_CIPHER:
3162 *((char **)arg)= mysql->options.ssl_cipher;
3163 break;
3164 case MYSQL_OPT_SSL_CRL:
3165 *((char **)arg)= mysql->options.extension ? mysql->options.ssl_cipher : NULL;
3166 break;
3167 case MYSQL_OPT_SSL_CRLPATH:
3168 *((char **)arg)= mysql->options.extension ? mysql->options.extension->ssl_crlpath : NULL;
3169 break;
3170 case MYSQL_OPT_CONNECT_ATTRS:
3171 /* mysql_get_optionsv(mysql, MYSQL_OPT_CONNECT_ATTRS, keys, vals, elements) */
3172 {
3173 unsigned int i, *elements;
3174 char **key= NULL;
3175 void *arg1;
3176 char **val= NULL;
3177
3178 if (arg)
3179 key= *(char ***)arg;
3180
3181 arg1= va_arg(ap, char **);
3182 if (arg1)
3183 val= *(char ***)arg1;
3184
3185 if (!(elements= va_arg(ap, unsigned int *)))
3186 goto error;
3187
3188 *elements= 0;
3189
3190 if (!mysql->options.extension ||
3191 !hash_inited(&mysql->options.extension->connect_attrs))
3192 break;
3193
3194 *elements= mysql->options.extension->connect_attrs.records;
3195
3196 if (val || key)
3197 {
3198 for (i=0; i < *elements; i++)
3199 {
3200 uchar *p= hash_element(&mysql->options.extension->connect_attrs, i);
3201 if (key)
3202 key[i]= (char *)p;
3203 p+= strlen((char *)p) + 1;
3204 if (val)
3205 val[i]= (char *)p;
3206 }
3207 }
3208 }
3209 break;
3210 case MYSQL_OPT_MAX_ALLOWED_PACKET:
3211 *((unsigned long *)arg)= (mysql) ? mysql->options.max_allowed_packet :
3212 max_allowed_packet;
3213 break;
3214 case MYSQL_OPT_NET_BUFFER_LENGTH:
3215 *((unsigned long *)arg)= net_buffer_length;
3216 break;
3217 case MYSQL_SECURE_AUTH:
3218 *((my_bool *)arg)= mysql->options.secure_auth;
3219 break;
3220 case MYSQL_OPT_BIND:
3221 *((char **)arg)= mysql->options.bind_address;
3222 break;
3223 case MARIADB_OPT_TLS_CIPHER_STRENGTH:
3224 *((unsigned int *)arg) = mysql->options.extension ? mysql->options.extension->tls_cipher_strength : 0;
3225 break;
3226 case MARIADB_OPT_SSL_FP:
3227 case MARIADB_OPT_TLS_PEER_FP:
3228 *((char **)arg)= mysql->options.extension ? mysql->options.extension->tls_fp : NULL;
3229 break;
3230 case MARIADB_OPT_SSL_FP_LIST:
3231 case MARIADB_OPT_TLS_PEER_FP_LIST:
3232 *((char **)arg)= mysql->options.extension ? mysql->options.extension->tls_fp_list : NULL;
3233 break;
3234 case MARIADB_OPT_TLS_PASSPHRASE:
3235 *((char **)arg)= mysql->options.extension ? mysql->options.extension->tls_pw : NULL;
3236 break;
3237 case MARIADB_OPT_CONNECTION_READ_ONLY:
3238 *((my_bool *)arg)= mysql->options.extension ? mysql->options.extension->read_only : 0;
3239 break;
3240 case MARIADB_OPT_USERDATA:
3241 /* nysql_get_optionv(mysql, MARIADB_OPT_USERDATA, key, value) */
3242 {
3243 uchar *p;
3244 void *data= va_arg(ap, void *);
3245 char *key= (char *)arg;
3246 if (key && data && mysql->options.extension && hash_inited(&mysql->options.extension->userdata) &&
3247 (p= (uchar *)hash_search(&mysql->options.extension->userdata, (uchar *)key,
3248 (uint)strlen((char *)key))))
3249 {
3250 p+= strlen(key) + 1;
3251 *((void **)data)= *((void **)p);
3252 break;
3253 }
3254 if (data)
3255 *((void **)data)= NULL;
3256 }
3257 break;
3258 case MARIADB_OPT_CONNECTION_HANDLER:
3259 *((char **)arg)= mysql->options.extension ? mysql->options.extension->connection_handler : NULL;
3260 break;
3261 case MARIADB_OPT_IO_WAIT:
3262 *((int(**)(my_socket, my_bool, int))arg) = mysql->options.extension ? mysql->options.extension->io_wait : NULL;
3263 break;
3264 default:
3265 va_end(ap);
3266 SET_CLIENT_ERROR(mysql, CR_NOT_IMPLEMENTED, SQLSTATE_UNKNOWN, 0);
3267 return(1);
3268 }
3269 va_end(ap);
3270 return(0);
3271error:
3272 va_end(ap);
3273 return(1);
3274}
3275
3276int STDCALL mysql_get_option(MYSQL *mysql, enum mysql_option option, void *arg)
3277{
3278 return mysql_get_optionv(mysql, option, arg);
3279}
3280
3281int STDCALL
3282mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg)
3283{
3284 return mysql_optionsv(mysql, option, arg);
3285}
3286
3287int STDCALL
3288mysql_options4(MYSQL *mysql,enum mysql_option option, const void *arg1, const void *arg2)
3289{
3290 return mysql_optionsv(mysql, option, arg1, arg2);
3291}
3292/****************************************************************************
3293** Functions to get information from the MySQL structure
3294** These are functions to make shared libraries more usable.
3295****************************************************************************/
3296
3297/* MYSQL_RES */
3298my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res)
3299{
3300 return res->row_count;
3301}
3302
3303unsigned int STDCALL mysql_num_fields(MYSQL_RES *res)
3304{
3305 return res->field_count;
3306}
3307
3308/* deprecated */
3309my_bool STDCALL mysql_eof(MYSQL_RES *res)
3310{
3311 return res->eof;
3312}
3313
3314MYSQL_FIELD * STDCALL mysql_fetch_field_direct(MYSQL_RES *res,uint fieldnr)
3315{
3316 return &(res)->fields[fieldnr];
3317}
3318
3319MYSQL_FIELD * STDCALL mysql_fetch_fields(MYSQL_RES *res)
3320{
3321 return (res)->fields;
3322}
3323
3324MYSQL_ROWS * STDCALL mysql_row_tell(MYSQL_RES *res)
3325{
3326 return res->data_cursor;
3327}
3328
3329uint STDCALL mysql_field_tell(MYSQL_RES *res)
3330{
3331 return (res)->current_field;
3332}
3333
3334/* MYSQL */
3335
3336unsigned int STDCALL mysql_field_count(MYSQL *mysql)
3337{
3338 return mysql->field_count;
3339}
3340
3341my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql)
3342{
3343 return (mysql)->affected_rows;
3344}
3345
3346my_bool STDCALL mysql_autocommit(MYSQL *mysql, my_bool mode)
3347{
3348 return((my_bool) mysql_real_query(mysql, (mode) ? "SET autocommit=1" :
3349 "SET autocommit=0", 16));
3350}
3351
3352my_bool STDCALL mysql_commit(MYSQL *mysql)
3353{
3354 return((my_bool)mysql_real_query(mysql, "COMMIT", (unsigned long)strlen("COMMIT")));
3355}
3356
3357my_bool STDCALL mysql_rollback(MYSQL *mysql)
3358{
3359 return((my_bool)mysql_real_query(mysql, "ROLLBACK", (unsigned long)strlen("ROLLBACK")));
3360}
3361
3362my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql)
3363{
3364 return (mysql)->insert_id;
3365}
3366
3367uint STDCALL mysql_errno(MYSQL *mysql)
3368{
3369 return mysql ? mysql->net.last_errno : 0;
3370}
3371
3372const char * STDCALL mysql_error(MYSQL *mysql)
3373{
3374 return mysql ? (mysql)->net.last_error : (char *)"";
3375}
3376
3377const char *STDCALL mysql_info(MYSQL *mysql)
3378{
3379 return (mysql)->info;
3380}
3381
3382my_bool STDCALL mysql_more_results(MYSQL *mysql)
3383{
3384 return(test(mysql->server_status & SERVER_MORE_RESULTS_EXIST));
3385}
3386
3387int STDCALL mysql_next_result(MYSQL *mysql)
3388{
3389
3390 /* make sure communication is not blocking */
3391 if (mysql->status != MYSQL_STATUS_READY)
3392 {
3393 SET_CLIENT_ERROR(mysql, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0);
3394 return(1);
3395 }
3396
3397 /* clear error, and mysql status variables */
3398 CLEAR_CLIENT_ERROR(mysql);
3399 mysql->affected_rows = (ulonglong) ~0;
3400
3401 if (mysql->server_status & SERVER_MORE_RESULTS_EXIST)
3402 {
3403 return(mysql->methods->db_read_query_result(mysql));
3404 }
3405
3406 return(-1);
3407}
3408
3409ulong STDCALL mysql_thread_id(MYSQL *mysql)
3410{
3411 return (mysql)->thread_id;
3412}
3413
3414const char * STDCALL mysql_character_set_name(MYSQL *mysql)
3415{
3416 return mysql->charset->csname;
3417}
3418
3419
3420uint STDCALL mysql_thread_safe(void)
3421{
3422#ifdef THREAD
3423 return 1;
3424#else
3425 return 0;
3426#endif
3427}
3428
3429/****************************************************************************
3430** Some support functions
3431****************************************************************************/
3432
3433/*
3434** Add escape characters to a string (blob?) to make it suitable for a insert
3435** to should at least have place for length*2+1 chars
3436** Returns the length of the to string
3437*/
3438
3439ulong STDCALL
3440mysql_escape_string(char *to,const char *from, ulong length)
3441{
3442 return (ulong)mysql_cset_escape_slashes(ma_default_charset_info, to, from, length);
3443}
3444
3445ulong STDCALL
3446mysql_real_escape_string(MYSQL *mysql, char *to,const char *from,
3447 ulong length)
3448{
3449 if (mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES)
3450 return (ulong)mysql_cset_escape_quotes(mysql->charset, to, from, length);
3451 else
3452 return (ulong)mysql_cset_escape_slashes(mysql->charset, to, from, length);
3453}
3454
3455static void mariadb_get_charset_info(MYSQL *mysql, MY_CHARSET_INFO *cs)
3456{
3457 if (!cs)
3458 return;
3459
3460 cs->number= mysql->charset->nr;
3461 cs->csname= mysql->charset->csname;
3462 cs->name= mysql->charset->name;
3463 cs->state= 0;
3464 cs->comment= NULL;
3465 cs->dir= NULL;
3466 cs->mbminlen= mysql->charset->char_minlen;
3467 cs->mbmaxlen= mysql->charset->char_maxlen;
3468
3469 return;
3470}
3471
3472void STDCALL mysql_get_character_set_info(MYSQL *mysql, MY_CHARSET_INFO *cs)
3473{
3474 mariadb_get_charset_info(mysql, cs);
3475}
3476
3477int STDCALL mysql_set_character_set(MYSQL *mysql, const char *csname)
3478{
3479 const MARIADB_CHARSET_INFO *cs;
3480
3481 if (!csname)
3482 goto error;
3483
3484 if ((cs= mysql_find_charset_name(csname)))
3485 {
3486 char buff[64];
3487
3488 snprintf(buff, 63, "SET NAMES %s", cs->csname);
3489 if (!mysql_real_query(mysql, buff, (unsigned long)strlen(buff)))
3490 {
3491 mysql->charset= cs;
3492 return(0);
3493 }
3494 }
3495
3496error:
3497 my_set_error(mysql, CR_CANT_READ_CHARSET, SQLSTATE_UNKNOWN,
3498 0, csname, "compiled_in");
3499 return(mysql->net.last_errno);
3500}
3501
3502unsigned int STDCALL mysql_warning_count(MYSQL *mysql)
3503{
3504 return mysql->warning_count;
3505}
3506
3507const char * STDCALL mysql_sqlstate(MYSQL *mysql)
3508{
3509 return mysql->net.sqlstate;
3510}
3511
3512#ifndef _WIN32
3513#include <signal.h>
3514static void ignore_sigpipe()
3515{
3516 signal(SIGPIPE, SIG_IGN);
3517}
3518#else
3519#define ignore_sigpipe()
3520#endif
3521
3522#ifdef _WIN32
3523static int mysql_once_init()
3524#else
3525static void mysql_once_init()
3526#endif
3527{
3528 ma_init(); /* Will init threads */
3529 init_client_errs();
3530 get_default_configuration_dirs();
3531 set_default_charset_by_name(MARIADB_DEFAULT_CHARSET, 0);
3532 if (mysql_client_plugin_init())
3533 {
3534#ifdef _WIN32
3535 return 1;
3536#else
3537 return;
3538#endif
3539 }
3540 if (!mysql_port)
3541 {
3542 struct servent *serv_ptr;
3543 char *env;
3544
3545 mysql_port = MARIADB_PORT;
3546 if ((serv_ptr = getservbyname("mysql", "tcp")))
3547 mysql_port = (uint)ntohs((ushort)serv_ptr->s_port);
3548 if ((env = getenv("MYSQL_TCP_PORT")))
3549 mysql_port =(uint)atoi(env);
3550 }
3551 if (!mysql_unix_port)
3552 {
3553 char *env;
3554#ifdef _WIN32
3555 mysql_unix_port = (char*)MARIADB_NAMEDPIPE;
3556#else
3557 mysql_unix_port = (char*)MARIADB_UNIX_ADDR;
3558#endif
3559 if ((env = getenv("MYSQL_UNIX_PORT")) ||
3560 (env = getenv("MARIADB_UNIX_PORT")))
3561 mysql_unix_port = env;
3562 }
3563 if (!mysql_ps_subsystem_initialized)
3564 mysql_init_ps_subsystem();
3565#ifdef HAVE_TLS
3566 ma_tls_start(0, 0);
3567#endif
3568 ignore_sigpipe();
3569 mysql_client_init = 1;
3570#ifdef _WIN32
3571 return 0;
3572#endif
3573}
3574
3575#ifdef _WIN32
3576static INIT_ONCE init_once= INIT_ONCE_STATIC_INIT;
3577BOOL CALLBACK win_init_once(
3578 PINIT_ONCE InitOnce,
3579 PVOID Parameter,
3580 PVOID *lpContext)
3581{
3582 return !mysql_once_init();
3583 return TRUE;
3584}
3585#else
3586static pthread_once_t init_once = PTHREAD_ONCE_INIT;
3587#endif
3588
3589int STDCALL mysql_server_init(int argc __attribute__((unused)),
3590 char **argv __attribute__((unused)),
3591 char **groups __attribute__((unused)))
3592{
3593#ifdef _WIN32
3594 BOOL ret = InitOnceExecuteOnce(&init_once, win_init_once, NULL, NULL);
3595 return ret? 0: 1;
3596#else
3597 return pthread_once(&init_once, mysql_once_init);
3598#endif
3599}
3600
3601void STDCALL mysql_server_end(void)
3602{
3603 if (!mysql_client_init)
3604 return;
3605
3606 release_configuration_dirs();
3607 mysql_client_plugin_deinit();
3608
3609 list_free(pvio_callback, 0);
3610 if (ma_init_done)
3611 ma_end(0);
3612#ifdef HAVE_TLS
3613 ma_pvio_tls_end();
3614#endif
3615 mysql_client_init= 0;
3616 ma_init_done= 0;
3617#ifdef WIN32
3618 init_once = (INIT_ONCE)INIT_ONCE_STATIC_INIT;
3619#else
3620 init_once = (pthread_once_t)PTHREAD_ONCE_INIT;
3621#endif
3622}
3623
3624my_bool STDCALL mysql_thread_init(void)
3625{
3626 return 0;
3627}
3628
3629void STDCALL mysql_thread_end(void)
3630{
3631}
3632
3633int STDCALL mysql_set_server_option(MYSQL *mysql,
3634 enum enum_mysql_set_option option)
3635{
3636 char buffer[2];
3637 int2store(buffer, (uint)option);
3638 return(ma_simple_command(mysql, COM_SET_OPTION, buffer, sizeof(buffer), 0, 0));
3639}
3640
3641ulong STDCALL mysql_get_client_version(void)
3642{
3643 return MARIADB_VERSION_ID;
3644}
3645
3646ulong STDCALL mysql_hex_string(char *to, const char *from, unsigned long len)
3647{
3648 char *start= to;
3649 char hexdigits[]= "0123456789ABCDEF";
3650
3651 while (len--)
3652 {
3653 *to++= hexdigits[((unsigned char)*from) >> 4];
3654 *to++= hexdigits[((unsigned char)*from) & 0x0F];
3655 from++;
3656 }
3657 *to= 0;
3658 return (ulong)(to - start);
3659}
3660
3661my_bool STDCALL mariadb_connection(MYSQL *mysql)
3662{
3663 return (strstr(mysql->server_version, "MariaDB") ||
3664 strstr(mysql->server_version, "-maria-"));
3665}
3666
3667const char * STDCALL
3668mysql_get_server_name(MYSQL *mysql)
3669{
3670 if (mysql->options.extension &&
3671 mysql->options.extension->db_driver != NULL)
3672 return mysql->options.extension->db_driver->name;
3673 return mariadb_connection(mysql) ? "MariaDB" : "MySQL";
3674}
3675
3676static my_socket mariadb_get_socket(MYSQL *mysql)
3677{
3678 my_socket sock= INVALID_SOCKET;
3679 if (mysql->net.pvio)
3680 {
3681 ma_pvio_get_handle(mysql->net.pvio, &sock);
3682
3683 }
3684 /* if an asynchronous connect is in progress, we need to obtain
3685 pvio handle from async_context until the connection was
3686 successfully established.
3687 */
3688 else if (mysql->options.extension && mysql->options.extension->async_context &&
3689 mysql->options.extension->async_context->pvio)
3690 {
3691 ma_pvio_get_handle(mysql->options.extension->async_context->pvio, &sock);
3692 }
3693 return sock;
3694}
3695
3696my_socket STDCALL
3697mysql_get_socket(MYSQL *mysql)
3698{
3699 return mariadb_get_socket(mysql);
3700}
3701
3702MARIADB_CHARSET_INFO * STDCALL mariadb_get_charset_by_name(const char *csname)
3703{
3704 return (MARIADB_CHARSET_INFO *)mysql_find_charset_name(csname);
3705}
3706
3707MARIADB_CHARSET_INFO * STDCALL mariadb_get_charset_by_nr(unsigned int csnr)
3708{
3709 return (MARIADB_CHARSET_INFO *)mysql_find_charset_nr(csnr);
3710}
3711
3712my_bool mariadb_get_infov(MYSQL *mysql, enum mariadb_value value, void *arg, ...)
3713{
3714 va_list ap;
3715
3716 va_start(ap, arg);
3717
3718 switch(value) {
3719 case MARIADB_MAX_ALLOWED_PACKET:
3720 *((size_t *)arg)= (size_t)max_allowed_packet;
3721 break;
3722 case MARIADB_NET_BUFFER_LENGTH:
3723 *((size_t *)arg)= (size_t)net_buffer_length;
3724 break;
3725 case MARIADB_CONNECTION_ERROR_ID:
3726 if (!mysql)
3727 goto error;
3728 *((unsigned int *)arg)= mysql->net.last_errno;
3729 break;
3730 case MARIADB_CONNECTION_ERROR:
3731 if (!mysql)
3732 goto error;
3733 *((char **)arg)= mysql->net.last_error;
3734 break;
3735 case MARIADB_CONNECTION_SQLSTATE:
3736 if (!mysql)
3737 goto error;
3738 *((char **)arg)= mysql->net.sqlstate;
3739 break;
3740 case MARIADB_CONNECTION_TLS_VERSION:
3741 #ifdef HAVE_TLS
3742 if (mysql && mysql->net.pvio && mysql->net.pvio->ctls)
3743 *((char **)arg)= (char *)ma_pvio_tls_get_protocol_version(mysql->net.pvio->ctls);
3744 else
3745 #endif
3746 goto error;
3747 break;
3748 case MARIADB_CONNECTION_TLS_VERSION_ID:
3749 #ifdef HAVE_TLS
3750 if (mysql && mysql->net.pvio && mysql->net.pvio->ctls)
3751 *((unsigned int *)arg)= ma_pvio_tls_get_protocol_version_id(mysql->net.pvio->ctls);
3752 else
3753 #endif
3754 goto error;
3755 break;
3756 case MARIADB_TLS_LIBRARY:
3757#ifdef HAVE_TLS
3758 *((const char **)arg)= tls_library_version;
3759#else
3760 *((char **)arg)= "Off";
3761#endif
3762 break;
3763 case MARIADB_CLIENT_VERSION:
3764 *((const char **)arg)= MARIADB_CLIENT_VERSION_STR;
3765 break;
3766 case MARIADB_CLIENT_VERSION_ID:
3767 *((size_t *)arg)= MARIADB_VERSION_ID;
3768 break;
3769 case MARIADB_CONNECTION_SERVER_VERSION:
3770 if (mysql)
3771 *((char **)arg)= mysql->server_version;
3772 else
3773 goto error;
3774 break;
3775 case MARIADB_CONNECTION_SERVER_TYPE:
3776 if (mysql)
3777 *((const char **)arg)= mariadb_connection(mysql) ? "MariaDB" : "MySQL";
3778 else
3779 goto error;
3780 break;
3781 case MARIADB_CONNECTION_SERVER_VERSION_ID:
3782 if (mysql)
3783 *((size_t *)arg)= mariadb_server_version_id(mysql);
3784 else
3785 goto error;
3786 break;
3787 case MARIADB_CONNECTION_PROTOCOL_VERSION_ID:
3788 if (mysql)
3789 *((unsigned int *)arg)= mysql->protocol_version;
3790 else
3791 goto error;
3792 break;
3793 case MARIADB_CONNECTION_MARIADB_CHARSET_INFO:
3794 if (mysql)
3795 mariadb_get_charset_info(mysql, (MY_CHARSET_INFO *)arg);
3796 else
3797 goto error;
3798 break;
3799 case MARIADB_CONNECTION_SOCKET:
3800 if (mysql)
3801 *((my_socket *)arg)= mariadb_get_socket(mysql);
3802 else
3803 goto error;
3804 break;
3805 case MARIADB_CONNECTION_TYPE:
3806 if (mysql && mysql->net.pvio)
3807 *((int *)arg)= (int)mysql->net.pvio->type;
3808 else
3809 goto error;
3810 break;
3811 case MARIADB_CONNECTION_ASYNC_TIMEOUT_MS:
3812 if (mysql && mysql->options.extension && mysql->options.extension->async_context)
3813 *((unsigned int *)arg)= mysql->options.extension->async_context->timeout_value;
3814 break;
3815 case MARIADB_CONNECTION_ASYNC_TIMEOUT:
3816 if (mysql && mysql->options.extension && mysql->options.extension->async_context)
3817 {
3818 unsigned int timeout= mysql->options.extension->async_context->timeout_value;
3819 if (timeout > UINT_MAX - 999)
3820 *((unsigned int *)arg)= (timeout - 1)/1000 + 1;
3821 else
3822 *((unsigned int *)arg)= (timeout+999)/1000;
3823 }
3824 break;
3825 case MARIADB_CHARSET_NAME:
3826 {
3827 char *name;
3828 name= va_arg(ap, char *);
3829 if (name)
3830 *((MARIADB_CHARSET_INFO **)arg)= (MARIADB_CHARSET_INFO *)mysql_find_charset_name(name);
3831 else
3832 goto error;
3833 }
3834 break;
3835 case MARIADB_CHARSET_ID:
3836 {
3837 unsigned int nr;
3838 nr= va_arg(ap, unsigned int);
3839 *((MARIADB_CHARSET_INFO **)arg)= (MARIADB_CHARSET_INFO *)mysql_find_charset_nr(nr);
3840 }
3841 break;
3842 case MARIADB_CONNECTION_SSL_CIPHER:
3843 #ifdef HAVE_TLS
3844 if (mysql && mysql->net.pvio && mysql->net.pvio->ctls)
3845 *((char **)arg)= (char *)ma_pvio_tls_cipher(mysql->net.pvio->ctls);
3846 else
3847 #endif
3848 goto error;
3849 break;
3850 case MARIADB_CLIENT_ERRORS:
3851 *((char ***)arg)= (char **)client_errors;
3852 break;
3853 case MARIADB_CONNECTION_INFO:
3854 if (mysql)
3855 *((char **)arg)= (char *)mysql->info;
3856 else
3857 goto error;
3858 break;
3859 case MARIADB_CONNECTION_PVIO_TYPE:
3860 if (mysql && mysql->net.pvio)
3861 *((unsigned int *)arg)= (unsigned int)mysql->net.pvio->type;
3862 else
3863 goto error;
3864 break;
3865 case MARIADB_CONNECTION_SCHEMA:
3866 if (mysql)
3867 *((char **)arg)= mysql->db;
3868 else
3869 goto error;
3870 break;
3871 case MARIADB_CONNECTION_USER:
3872 if (mysql)
3873 *((char **)arg)= mysql->user;
3874 else
3875 goto error;
3876 break;
3877 case MARIADB_CONNECTION_PORT:
3878 if (mysql)
3879 *((unsigned int *)arg)= mysql->port;
3880 else
3881 goto error;
3882 break;
3883 case MARIADB_CONNECTION_UNIX_SOCKET:
3884 if (mysql)
3885 *((char **)arg)= mysql->unix_socket;
3886 else
3887 goto error;
3888 break;
3889 case MARIADB_CONNECTION_HOST:
3890 if (mysql)
3891 *((char **)arg)= mysql->host;
3892 else
3893 goto error;
3894 break;
3895 case MARIADB_CONNECTION_SERVER_STATUS:
3896 if (mysql)
3897 *((unsigned int *)arg)= mysql->server_status;
3898 else
3899 goto error;
3900 break;
3901 case MARIADB_CONNECTION_SERVER_CAPABILITIES:
3902 if (mysql)
3903 *((unsigned long *)arg)= mysql->server_capabilities;
3904 else
3905 goto error;
3906 break;
3907 case MARIADB_CONNECTION_EXTENDED_SERVER_CAPABILITIES:
3908 if (mysql)
3909 *((unsigned long *)arg)= mysql->extension->mariadb_server_capabilities;
3910 else
3911 goto error;
3912 break;
3913 case MARIADB_CONNECTION_CLIENT_CAPABILITIES:
3914 if (mysql)
3915 *((unsigned long *)arg)= mysql->client_flag;
3916 else
3917 goto error;
3918 break;
3919 default:
3920 va_end(ap);
3921 return(-1);
3922 }
3923 va_end(ap);
3924 return(0);
3925error:
3926 va_end(ap);
3927 return(-1);
3928}
3929
3930my_bool STDCALL mariadb_get_info(MYSQL *mysql, enum mariadb_value value, void *arg)
3931{
3932 return mariadb_get_infov(mysql, value, arg);
3933}
3934
3935/*
3936 Immediately aborts connection, making all subsequent read/write operations fail.
3937 Does not invalidate memory used for mysql structure, nor closes any communication
3938 channels - mysql_close is still needed.
3939 Useful to break long query, in situation sending KILL is not possible.
3940*/
3941int STDCALL mariadb_cancel(MYSQL *mysql)
3942{
3943 if (!mysql || !mysql->net.pvio || !mysql->net.pvio->methods || !mysql->net.pvio->methods->shutdown)
3944 {
3945 return 1;
3946 }
3947 else
3948 {
3949 MARIADB_PVIO *pvio = mysql->net.pvio;
3950 return pvio->methods->shutdown(pvio);
3951 }
3952}
3953
3954/* compatibility functions for MariaDB */
3955void STDCALL
3956mysql_debug(const char *debug __attribute__((unused)))
3957{
3958 return;
3959}
3960
3961/********************************************************************
3962 mysql_net_ functions - low-level API to MySQL protocol
3963*********************************************************************/
3964ulong STDCALL mysql_net_read_packet(MYSQL *mysql)
3965{
3966 return ma_net_safe_read(mysql);
3967}
3968
3969ulong STDCALL mysql_net_field_length(uchar **packet)
3970{
3971 return net_field_length(packet);
3972}
3973
3974my_bool STDCALL mysql_embedded(void)
3975{
3976#ifdef EMBEDDED_LIBRARY
3977 return 1;
3978#else
3979 return 0;
3980#endif
3981}
3982
3983MYSQL_PARAMETERS *STDCALL
3984mysql_get_parameters(void)
3985{
3986 return &mariadb_internal_parameters;
3987}
3988
3989int STDCALL mysql_reset_connection(MYSQL *mysql)
3990{
3991 int rc;
3992
3993 /* check if connection handler is active */
3994 if (IS_CONNHDLR_ACTIVE(mysql))
3995 {
3996 if (mysql->extension->conn_hdlr->plugin && mysql->extension->conn_hdlr->plugin->reset)
3997 return(mysql->extension->conn_hdlr->plugin->reset(mysql));
3998 }
3999
4000 /* skip result sets */
4001 if (mysql->status == MYSQL_STATUS_USE_RESULT ||
4002 mysql->status == MYSQL_STATUS_GET_RESULT ||
4003 mysql->status & SERVER_MORE_RESULTS_EXIST)
4004 {
4005 mthd_my_skip_result(mysql);
4006 mysql->status= MYSQL_STATUS_READY;
4007 }
4008
4009 rc= ma_simple_command(mysql, COM_RESET_CONNECTION, 0, 0, 0, 0);
4010 if (rc && mysql->options.reconnect)
4011 {
4012 /* There is no big sense in resetting but we need reconnect */
4013 rc= ma_simple_command(mysql, COM_RESET_CONNECTION,0,0,0,0);
4014 }
4015 if (rc)
4016 return 1;
4017
4018 /* reset the connection in all active statements */
4019 ma_invalidate_stmts(mysql, "mysql_reset_connection()");
4020 free_old_query(mysql);
4021 mysql->status= MYSQL_STATUS_READY;
4022 mysql->affected_rows= ~(my_ulonglong)0;
4023 mysql->insert_id= 0;
4024 return 0;
4025}
4026
4027#undef STDCALL
4028/* API functions for usage in dynamic plugins */
4029struct st_mariadb_api MARIADB_API=
4030{
4031 mysql_num_rows,
4032 mysql_num_fields,
4033 mysql_eof,
4034 mysql_fetch_field_direct,
4035 mysql_fetch_fields,
4036 mysql_row_tell,
4037 mysql_field_tell,
4038 mysql_field_count,
4039 mysql_more_results,
4040 mysql_next_result,
4041 mysql_affected_rows,
4042 mysql_autocommit,
4043 mysql_commit,
4044 mysql_rollback,
4045 mysql_insert_id,
4046 mysql_errno,
4047 mysql_error,
4048 mysql_info,
4049 mysql_thread_id,
4050 mysql_character_set_name,
4051 mysql_get_character_set_info,
4052 mysql_set_character_set,
4053 mariadb_get_infov,
4054 mariadb_get_info,
4055 mysql_init,
4056 mysql_ssl_set,
4057 mysql_get_ssl_cipher,
4058 mysql_change_user,
4059 mysql_real_connect,
4060 mysql_close,
4061 mysql_select_db,
4062 mysql_query,
4063 mysql_send_query,
4064 mysql_read_query_result,
4065 mysql_real_query,
4066 mysql_shutdown,
4067 mysql_dump_debug_info,
4068 mysql_refresh,
4069 mysql_kill,
4070 mysql_ping,
4071 mysql_stat,
4072 mysql_get_server_info,
4073 mysql_get_server_version,
4074 mysql_get_host_info,
4075 mysql_get_proto_info,
4076 mysql_list_dbs,
4077 mysql_list_tables,
4078 mysql_list_fields,
4079 mysql_list_processes,
4080 mysql_store_result,
4081 mysql_use_result,
4082 mysql_options,
4083 mysql_free_result,
4084 mysql_data_seek,
4085 mysql_row_seek,
4086 mysql_field_seek,
4087 mysql_fetch_row,
4088 mysql_fetch_lengths,
4089 mysql_fetch_field,
4090 mysql_escape_string,
4091 mysql_real_escape_string,
4092 mysql_thread_safe,
4093 mysql_warning_count,
4094 mysql_sqlstate,
4095 mysql_server_init,
4096 mysql_server_end,
4097 mysql_thread_end,
4098 mysql_thread_init,
4099 mysql_set_server_option,
4100 mysql_get_client_info,
4101 mysql_get_client_version,
4102 mariadb_connection,
4103 mysql_get_server_name,
4104 mariadb_get_charset_by_name,
4105 mariadb_get_charset_by_nr,
4106 mariadb_convert_string,
4107 mysql_optionsv,
4108 mysql_get_optionv,
4109 mysql_get_option,
4110 mysql_hex_string,
4111 mysql_get_socket,
4112 mysql_get_timeout_value,
4113 mysql_get_timeout_value_ms,
4114 mariadb_reconnect,
4115 mysql_stmt_init,
4116 mysql_stmt_prepare,
4117 mysql_stmt_execute,
4118 mysql_stmt_fetch,
4119 mysql_stmt_fetch_column,
4120 mysql_stmt_store_result,
4121 mysql_stmt_param_count,
4122 mysql_stmt_attr_set,
4123 mysql_stmt_attr_get,
4124 mysql_stmt_bind_param,
4125 mysql_stmt_bind_result,
4126 mysql_stmt_close,
4127 mysql_stmt_reset,
4128 mysql_stmt_free_result,
4129 mysql_stmt_send_long_data,
4130 mysql_stmt_result_metadata,
4131 mysql_stmt_param_metadata,
4132 mysql_stmt_errno,
4133 mysql_stmt_error,
4134 mysql_stmt_sqlstate,
4135 mysql_stmt_row_seek,
4136 mysql_stmt_row_tell,
4137 mysql_stmt_data_seek,
4138 mysql_stmt_num_rows,
4139 mysql_stmt_affected_rows,
4140 mysql_stmt_insert_id,
4141 mysql_stmt_field_count,
4142 mysql_stmt_next_result,
4143 mysql_stmt_more_results,
4144 mariadb_stmt_execute_direct,
4145 mysql_reset_connection
4146};
4147
4148/*
4149 * Default methods for a connection. These methods are
4150 * stored in mysql->methods and can be overwritten by
4151 * a plugin, e.g. for using another database
4152 */
4153struct st_mariadb_methods MARIADB_DEFAULT_METHODS = {
4154 /* open a connection */
4155 mthd_my_real_connect,
4156 /* close connection */
4157 mysql_close_slow_part,
4158 /* send command to server */
4159 mthd_my_send_cmd,
4160 /* skip result set */
4161 mthd_my_skip_result,
4162 /* read response packet */
4163 mthd_my_read_query_result,
4164 /* read all rows from a result set */
4165 mthd_my_read_rows,
4166 /* read one/next row */
4167 mthd_my_read_one_row,
4168 /* check if datatype is supported */
4169 mthd_supported_buffer_type,
4170 /* read response packet from prepare */
4171 mthd_stmt_read_prepare_response,
4172 /* read response from stmt execute */
4173 mthd_my_read_query_result,
4174 /* get result set metadata for a prepared statement */
4175 mthd_stmt_get_result_metadata,
4176 /* get param metadata for a prepared statement */
4177 mthd_stmt_get_param_metadata,
4178 /* read all rows (buffered) */
4179 mthd_stmt_read_all_rows,
4180 /* fetch one row (unbuffered) */
4181 mthd_stmt_fetch_row,
4182 /* store values in bind buffer */
4183 mthd_stmt_fetch_to_bind,
4184 /* skip unbuffered stmt result */
4185 mthd_stmt_flush_unbuffered,
4186 /* set error */
4187 my_set_error,
4188 /* invalidate statements */
4189 ma_invalidate_stmts,
4190 /* API functions */
4191 &MARIADB_API
4192};
4193