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