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