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