This source file includes following definitions.
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD_PRIVATE
- MYSQLND_METHOD
- MYSQLND_METHOD
- mysqlnd_switch_to_ssl_if_needed
- MYSQLND_METHOD
- mysqlnd_run_authentication
- mysqlnd_connect_run_authentication
- MYSQLND_METHOD
- mysqlnd_connect
- mysqlnd_stream_array_check_for_readiness
- mysqlnd_stream_array_to_fd_set
- mysqlnd_stream_array_from_fd_set
- mysqlnd_poll
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- mysqlnd_old_escape_string
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD_PRIVATE
- MYSQLND_METHOD_PRIVATE
- MYSQLND_METHOD_PRIVATE
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- mysqlnd_get_client_info
- mysqlnd_get_client_version
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- mysqlnd_field_type_name
- MYSQLND_METHOD
- MYSQLND_METHOD
- mysqlnd_escape_string_for_tx_name_in_comment
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_CLASS_METHODS_START
- MYSQLND_METHOD_PRIVATE
- MYSQLND_CLASS_METHODS_START
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 #include "php.h"
23 #include "mysqlnd.h"
24 #include "mysqlnd_wireprotocol.h"
25 #include "mysqlnd_priv.h"
26 #include "mysqlnd_result.h"
27 #include "mysqlnd_statistics.h"
28 #include "mysqlnd_charset.h"
29 #include "mysqlnd_debug.h"
30 #include "zend_smart_str.h"
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 extern MYSQLND_CHARSET *mysqlnd_charsets;
53
54
55
56 PHPAPI const char * const mysqlnd_old_passwd = "mysqlnd cannot connect to MySQL 4.1+ using the old insecure authentication. "
57 "Please use an administration tool to reset your password with the command SET PASSWORD = PASSWORD('your_existing_password'). This will "
58 "store a new, and more secure, hash value in mysql.user. If this user is used in other scripts executed by PHP 5.2 or earlier you might need to remove the old-passwords "
59 "flag from your my.cnf file";
60
61 PHPAPI const char * const mysqlnd_server_gone = "MySQL server has gone away";
62 PHPAPI const char * const mysqlnd_out_of_sync = "Commands out of sync; you can't run this command now";
63 PHPAPI const char * const mysqlnd_out_of_memory = "Out of memory";
64
65 PHPAPI MYSQLND_STATS *mysqlnd_global_stats = NULL;
66
67
68
69 static void
70 MYSQLND_METHOD(mysqlnd_conn_data, free_options)(MYSQLND_CONN_DATA * conn)
71 {
72 zend_bool pers = conn->persistent;
73
74 if (conn->options->charset_name) {
75 mnd_pefree(conn->options->charset_name, pers);
76 conn->options->charset_name = NULL;
77 }
78 if (conn->options->auth_protocol) {
79 mnd_pefree(conn->options->auth_protocol, pers);
80 conn->options->auth_protocol = NULL;
81 }
82 if (conn->options->num_commands) {
83 unsigned int i;
84 for (i = 0; i < conn->options->num_commands; i++) {
85
86 mnd_pefree(conn->options->init_commands[i], pers);
87 }
88 mnd_pefree(conn->options->init_commands, pers);
89 conn->options->init_commands = NULL;
90 }
91 if (conn->options->cfg_file) {
92 mnd_pefree(conn->options->cfg_file, pers);
93 conn->options->cfg_file = NULL;
94 }
95 if (conn->options->cfg_section) {
96 mnd_pefree(conn->options->cfg_section, pers);
97 conn->options->cfg_section = NULL;
98 }
99 if (conn->options->connect_attr) {
100 zend_hash_destroy(conn->options->connect_attr);
101 mnd_pefree(conn->options->connect_attr, pers);
102 conn->options->connect_attr = NULL;
103 }
104 }
105
106
107
108
109 static void
110 MYSQLND_METHOD(mysqlnd_conn_data, free_contents)(MYSQLND_CONN_DATA * conn)
111 {
112 zend_bool pers = conn->persistent;
113
114 DBG_ENTER("mysqlnd_conn_data::free_contents");
115
116 if (conn->current_result) {
117 conn->current_result->m.free_result(conn->current_result, TRUE);
118 conn->current_result = NULL;
119 }
120
121 if (conn->net) {
122 conn->net->data->m.free_contents(conn->net);
123 }
124
125 DBG_INF("Freeing memory of members");
126
127 if (conn->host) {
128 mnd_pefree(conn->host, pers);
129 conn->host = NULL;
130 }
131 if (conn->user) {
132 mnd_pefree(conn->user, pers);
133 conn->user = NULL;
134 }
135 if (conn->passwd) {
136 mnd_pefree(conn->passwd, pers);
137 conn->passwd = NULL;
138 }
139 if (conn->connect_or_select_db) {
140 mnd_pefree(conn->connect_or_select_db, pers);
141 conn->connect_or_select_db = NULL;
142 }
143 if (conn->unix_socket) {
144 mnd_pefree(conn->unix_socket, pers);
145 conn->unix_socket = NULL;
146 }
147 DBG_INF_FMT("scheme=%s", conn->scheme);
148 if (conn->scheme) {
149 mnd_pefree(conn->scheme, pers);
150 conn->scheme = NULL;
151 }
152 if (conn->server_version) {
153 mnd_pefree(conn->server_version, pers);
154 conn->server_version = NULL;
155 }
156 if (conn->host_info) {
157 mnd_pefree(conn->host_info, pers);
158 conn->host_info = NULL;
159 }
160 if (conn->auth_plugin_data) {
161 mnd_pefree(conn->auth_plugin_data, pers);
162 conn->auth_plugin_data = NULL;
163 }
164 if (conn->last_message) {
165 mnd_pefree(conn->last_message, pers);
166 conn->last_message = NULL;
167 }
168 if (conn->error_info->error_list) {
169 zend_llist_clean(conn->error_info->error_list);
170 mnd_pefree(conn->error_info->error_list, pers);
171 conn->error_info->error_list = NULL;
172 }
173 conn->charset = NULL;
174 conn->greet_charset = NULL;
175
176 DBG_VOID_RETURN;
177 }
178
179
180
181
182 static void
183 MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, dtor)(MYSQLND_CONN_DATA * conn)
184 {
185 DBG_ENTER("mysqlnd_conn_data::dtor");
186 DBG_INF_FMT("conn=%llu", conn->thread_id);
187
188 conn->m->free_contents(conn);
189 conn->m->free_options(conn);
190
191 if (conn->net) {
192 mysqlnd_net_free(conn->net, conn->stats, conn->error_info);
193 conn->net = NULL;
194 }
195
196 if (conn->protocol) {
197 mysqlnd_protocol_free(conn->protocol);
198 conn->protocol = NULL;
199 }
200
201 if (conn->stats) {
202 mysqlnd_stats_end(conn->stats, conn->persistent);
203 }
204
205 mnd_pefree(conn, conn->persistent);
206
207 DBG_VOID_RETURN;
208 }
209
210
211
212
213 static enum_func_status
214 MYSQLND_METHOD(mysqlnd_conn_data, simple_command_handle_response)(MYSQLND_CONN_DATA * conn, enum mysqlnd_packet_type ok_packet,
215 zend_bool silent, enum php_mysqlnd_server_command command,
216 zend_bool ignore_upsert_status)
217 {
218 enum_func_status ret = FAIL;
219
220 DBG_ENTER("mysqlnd_conn_data::simple_command_handle_response");
221 DBG_INF_FMT("silent=%u packet=%u command=%s", silent, ok_packet, mysqlnd_command_to_text[command]);
222
223 switch (ok_packet) {
224 case PROT_OK_PACKET:{
225 MYSQLND_PACKET_OK * ok_response = conn->protocol->m.get_ok_packet(conn->protocol, FALSE);
226 if (!ok_response) {
227 SET_OOM_ERROR(*conn->error_info);
228 break;
229 }
230 if (FAIL == (ret = PACKET_READ(ok_response, conn))) {
231 if (!silent) {
232 DBG_ERR_FMT("Error while reading %s's OK packet", mysqlnd_command_to_text[command]);
233 php_error_docref(NULL, E_WARNING, "Error while reading %s's OK packet. PID=%u",
234 mysqlnd_command_to_text[command], getpid());
235 }
236 } else {
237 DBG_INF_FMT("OK from server");
238 if (0xFF == ok_response->field_count) {
239
240 SET_CLIENT_ERROR(*conn->error_info, ok_response->error_no, ok_response->sqlstate, ok_response->error);
241 ret = FAIL;
242
243
244
245
246
247
248
249
250
251 conn->upsert_status->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
252 SET_ERROR_AFF_ROWS(conn);
253 } else {
254 SET_NEW_MESSAGE(conn->last_message, conn->last_message_len,
255 ok_response->message, ok_response->message_len,
256 conn->persistent);
257
258 if (!ignore_upsert_status) {
259 memset(conn->upsert_status, 0, sizeof(*conn->upsert_status));
260 conn->upsert_status->warning_count = ok_response->warning_count;
261 conn->upsert_status->server_status = ok_response->server_status;
262 conn->upsert_status->affected_rows = ok_response->affected_rows;
263 conn->upsert_status->last_insert_id = ok_response->last_insert_id;
264 }
265 }
266 }
267 PACKET_FREE(ok_response);
268 break;
269 }
270 case PROT_EOF_PACKET:{
271 MYSQLND_PACKET_EOF * ok_response = conn->protocol->m.get_eof_packet(conn->protocol, FALSE);
272 if (!ok_response) {
273 SET_OOM_ERROR(*conn->error_info);
274 break;
275 }
276 if (FAIL == (ret = PACKET_READ(ok_response, conn))) {
277 SET_CLIENT_ERROR(*conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE,
278 "Malformed packet");
279 if (!silent) {
280 DBG_ERR_FMT("Error while reading %s's EOF packet", mysqlnd_command_to_text[command]);
281 php_error_docref(NULL, E_WARNING, "Error while reading %s's EOF packet. PID=%d",
282 mysqlnd_command_to_text[command], getpid());
283 }
284 } else if (0xFF == ok_response->field_count) {
285
286 SET_CLIENT_ERROR(*conn->error_info, ok_response->error_no, ok_response->sqlstate, ok_response->error);
287 SET_ERROR_AFF_ROWS(conn);
288 } else if (0xFE != ok_response->field_count) {
289 SET_CLIENT_ERROR(*conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet");
290 if (!silent) {
291 DBG_ERR_FMT("EOF packet expected, field count wasn't 0xFE but 0x%2X", ok_response->field_count);
292 php_error_docref(NULL, E_WARNING, "EOF packet expected, field count wasn't 0xFE but 0x%2X",
293 ok_response->field_count);
294 }
295 } else {
296 DBG_INF_FMT("OK from server");
297 }
298 PACKET_FREE(ok_response);
299 break;
300 }
301 default:
302 SET_CLIENT_ERROR(*conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet");
303 php_error_docref(NULL, E_ERROR, "Wrong response packet %u passed to the function", ok_packet);
304 break;
305 }
306 DBG_INF(ret == PASS ? "PASS":"FAIL");
307 DBG_RETURN(ret);
308 }
309
310
311
312
313 static enum_func_status
314 MYSQLND_METHOD(mysqlnd_conn_data, simple_command_send_request)(MYSQLND_CONN_DATA * conn, enum php_mysqlnd_server_command command,
315 const zend_uchar * const arg, size_t arg_len, zend_bool silent, zend_bool ignore_upsert_status)
316 {
317 enum_func_status ret = PASS;
318 MYSQLND_PACKET_COMMAND * cmd_packet;
319
320 DBG_ENTER("mysqlnd_conn_data::simple_command_send_request");
321 DBG_INF_FMT("command=%s silent=%u", mysqlnd_command_to_text[command], silent);
322 DBG_INF_FMT("conn->server_status=%u", conn->upsert_status->server_status);
323 DBG_INF_FMT("sending %u bytes", arg_len + 1);
324
325 switch (CONN_GET_STATE(conn)) {
326 case CONN_READY:
327 break;
328 case CONN_QUIT_SENT:
329 SET_CLIENT_ERROR(*conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
330 DBG_ERR("Server is gone");
331 DBG_RETURN(FAIL);
332 default:
333 SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
334 DBG_ERR_FMT("Command out of sync. State=%u", CONN_GET_STATE(conn));
335 DBG_RETURN(FAIL);
336 }
337
338 SET_ERROR_AFF_ROWS(conn);
339 SET_EMPTY_ERROR(*conn->error_info);
340
341 cmd_packet = conn->protocol->m.get_command_packet(conn->protocol, FALSE);
342 if (!cmd_packet) {
343 SET_OOM_ERROR(*conn->error_info);
344 DBG_RETURN(FAIL);
345 }
346
347 cmd_packet->command = command;
348 if (arg && arg_len) {
349 cmd_packet->argument = arg;
350 cmd_packet->arg_len = arg_len;
351 }
352
353 MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_COM_QUIT + command - 1 );
354
355 if (! PACKET_WRITE(cmd_packet, conn)) {
356 if (!silent) {
357 DBG_ERR_FMT("Error while sending %s packet", mysqlnd_command_to_text[command]);
358 php_error(E_WARNING, "Error while sending %s packet. PID=%d", mysqlnd_command_to_text[command], getpid());
359 }
360 CONN_SET_STATE(conn, CONN_QUIT_SENT);
361 conn->m->send_close(conn);
362 DBG_ERR("Server is gone");
363 ret = FAIL;
364 }
365 PACKET_FREE(cmd_packet);
366 DBG_RETURN(ret);
367 }
368
369
370
371
372 static enum_func_status
373 MYSQLND_METHOD(mysqlnd_conn_data, simple_command)(MYSQLND_CONN_DATA * conn, enum php_mysqlnd_server_command command,
374 const zend_uchar * const arg, size_t arg_len, enum mysqlnd_packet_type ok_packet, zend_bool silent,
375 zend_bool ignore_upsert_status)
376 {
377 enum_func_status ret;
378 DBG_ENTER("mysqlnd_conn_data::simple_command");
379
380 ret = conn->m->simple_command_send_request(conn, command, arg, arg_len, silent, ignore_upsert_status);
381 if (PASS == ret && ok_packet != PROT_LAST) {
382 ret = conn->m->simple_command_handle_response(conn, ok_packet, silent, command, ignore_upsert_status);
383 }
384
385 DBG_INF(ret == PASS ? "PASS":"FAIL");
386 DBG_RETURN(ret);
387 }
388
389
390
391
392 static enum_func_status
393 MYSQLND_METHOD(mysqlnd_conn_data, set_server_option)(MYSQLND_CONN_DATA * const conn, enum_mysqlnd_server_option option)
394 {
395 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, set_server_option);
396 zend_uchar buffer[2];
397 enum_func_status ret = FAIL;
398 DBG_ENTER("mysqlnd_conn_data::set_server_option");
399 if (PASS == conn->m->local_tx_start(conn, this_func)) {
400
401 int2store(buffer, (unsigned int) option);
402 ret = conn->m->simple_command(conn, COM_SET_OPTION, buffer, sizeof(buffer), PROT_EOF_PACKET, FALSE, TRUE);
403
404 conn->m->local_tx_end(conn, this_func, ret);
405 }
406 DBG_RETURN(ret);
407 }
408
409
410
411
412 static enum_func_status
413 MYSQLND_METHOD(mysqlnd_conn_data, restart_psession)(MYSQLND_CONN_DATA * conn)
414 {
415 DBG_ENTER("mysqlnd_conn_data::restart_psession");
416 MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CONNECT_REUSED);
417
418 if (conn->last_message) {
419 mnd_pefree(conn->last_message, conn->persistent);
420 conn->last_message = NULL;
421 }
422 DBG_RETURN(PASS);
423 }
424
425
426
427
428 static enum_func_status
429 MYSQLND_METHOD(mysqlnd_conn_data, end_psession)(MYSQLND_CONN_DATA * conn)
430 {
431 DBG_ENTER("mysqlnd_conn_data::end_psession");
432 DBG_RETURN(PASS);
433 }
434
435
436
437
438 static enum_func_status
439 mysqlnd_switch_to_ssl_if_needed(
440 MYSQLND_CONN_DATA * conn,
441 const MYSQLND_PACKET_GREET * const greet_packet,
442 const MYSQLND_OPTIONS * const options,
443 zend_ulong mysql_flags)
444 {
445 enum_func_status ret = FAIL;
446 const MYSQLND_CHARSET * charset;
447 MYSQLND_PACKET_AUTH * auth_packet;
448 DBG_ENTER("mysqlnd_switch_to_ssl_if_needed");
449 DBG_INF_FMT("client_capability_flags=%lu", mysql_flags);
450 DBG_INF_FMT("CLIENT_LONG_PASSWORD= %d", mysql_flags & CLIENT_LONG_PASSWORD? 1:0);
451 DBG_INF_FMT("CLIENT_FOUND_ROWS= %d", mysql_flags & CLIENT_FOUND_ROWS? 1:0);
452 DBG_INF_FMT("CLIENT_LONG_FLAG= %d", mysql_flags & CLIENT_LONG_FLAG? 1:0);
453 DBG_INF_FMT("CLIENT_NO_SCHEMA= %d", mysql_flags & CLIENT_NO_SCHEMA? 1:0);
454 DBG_INF_FMT("CLIENT_COMPRESS= %d", mysql_flags & CLIENT_COMPRESS? 1:0);
455 DBG_INF_FMT("CLIENT_ODBC= %d", mysql_flags & CLIENT_ODBC? 1:0);
456 DBG_INF_FMT("CLIENT_LOCAL_FILES= %d", mysql_flags & CLIENT_LOCAL_FILES? 1:0);
457 DBG_INF_FMT("CLIENT_IGNORE_SPACE= %d", mysql_flags & CLIENT_IGNORE_SPACE? 1:0);
458 DBG_INF_FMT("CLIENT_PROTOCOL_41= %d", mysql_flags & CLIENT_PROTOCOL_41? 1:0);
459 DBG_INF_FMT("CLIENT_INTERACTIVE= %d", mysql_flags & CLIENT_INTERACTIVE? 1:0);
460 DBG_INF_FMT("CLIENT_SSL= %d", mysql_flags & CLIENT_SSL? 1:0);
461 DBG_INF_FMT("CLIENT_IGNORE_SIGPIPE= %d", mysql_flags & CLIENT_IGNORE_SIGPIPE? 1:0);
462 DBG_INF_FMT("CLIENT_TRANSACTIONS= %d", mysql_flags & CLIENT_TRANSACTIONS? 1:0);
463 DBG_INF_FMT("CLIENT_RESERVED= %d", mysql_flags & CLIENT_RESERVED? 1:0);
464 DBG_INF_FMT("CLIENT_SECURE_CONNECTION=%d", mysql_flags & CLIENT_SECURE_CONNECTION? 1:0);
465 DBG_INF_FMT("CLIENT_MULTI_STATEMENTS=%d", mysql_flags & CLIENT_MULTI_STATEMENTS? 1:0);
466 DBG_INF_FMT("CLIENT_MULTI_RESULTS= %d", mysql_flags & CLIENT_MULTI_RESULTS? 1:0);
467 DBG_INF_FMT("CLIENT_PS_MULTI_RESULTS=%d", mysql_flags & CLIENT_PS_MULTI_RESULTS? 1:0);
468 DBG_INF_FMT("CLIENT_CONNECT_ATTRS= %d", mysql_flags & CLIENT_PLUGIN_AUTH? 1:0);
469 DBG_INF_FMT("CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA= %d", mysql_flags & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA? 1:0);
470 DBG_INF_FMT("CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS= %d", mysql_flags & CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS? 1:0);
471 DBG_INF_FMT("CLIENT_SESSION_TRACK= %d", mysql_flags & CLIENT_SESSION_TRACK? 1:0);
472 DBG_INF_FMT("CLIENT_SSL_DONT_VERIFY_SERVER_CERT= %d", mysql_flags & CLIENT_SSL_DONT_VERIFY_SERVER_CERT? 1:0);
473 DBG_INF_FMT("CLIENT_SSL_VERIFY_SERVER_CERT= %d", mysql_flags & CLIENT_SSL_VERIFY_SERVER_CERT? 1:0);
474 DBG_INF_FMT("CLIENT_REMEMBER_OPTIONS= %d", mysql_flags & CLIENT_REMEMBER_OPTIONS? 1:0);
475
476 auth_packet = conn->protocol->m.get_auth_packet(conn->protocol, FALSE);
477 if (!auth_packet) {
478 SET_OOM_ERROR(*conn->error_info);
479 goto end;
480 }
481 auth_packet->client_flags = mysql_flags;
482 auth_packet->max_packet_size = MYSQLND_ASSEMBLED_PACKET_MAX_SIZE;
483
484 if (options->charset_name && (charset = mysqlnd_find_charset_name(options->charset_name))) {
485 auth_packet->charset_no = charset->nr;
486 } else {
487 auth_packet->charset_no = greet_packet->charset_no;
488 }
489
490 #ifdef MYSQLND_SSL_SUPPORTED
491 if (mysql_flags & CLIENT_SSL) {
492 zend_bool server_has_ssl = (greet_packet->server_capabilities & CLIENT_SSL)? TRUE:FALSE;
493 if (server_has_ssl == FALSE) {
494 goto close_conn;
495 } else {
496 enum mysqlnd_ssl_peer verify = mysql_flags & CLIENT_SSL_VERIFY_SERVER_CERT?
497 MYSQLND_SSL_PEER_VERIFY:
498 (mysql_flags & CLIENT_SSL_DONT_VERIFY_SERVER_CERT?
499 MYSQLND_SSL_PEER_DONT_VERIFY:
500 MYSQLND_SSL_PEER_DEFAULT);
501 DBG_INF("Switching to SSL");
502 if (!PACKET_WRITE(auth_packet, conn)) {
503 goto close_conn;
504 }
505
506 conn->net->data->m.set_client_option(conn->net, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (const char *) &verify);
507
508 if (FAIL == conn->net->data->m.enable_ssl(conn->net)) {
509 goto end;
510 }
511 }
512 }
513 #else
514 auth_packet->client_flags &= ~CLIENT_SSL;
515 if (!PACKET_WRITE(auth_packet, conn)) {
516 goto close_conn;
517 }
518 #endif
519 ret = PASS;
520 end:
521 PACKET_FREE(auth_packet);
522 DBG_RETURN(ret);
523
524 close_conn:
525 CONN_SET_STATE(conn, CONN_QUIT_SENT);
526 conn->m->send_close(conn);
527 SET_CLIENT_ERROR(*conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
528 PACKET_FREE(auth_packet);
529 DBG_RETURN(ret);
530 }
531
532
533
534
535 static struct st_mysqlnd_authentication_plugin *
536 MYSQLND_METHOD(mysqlnd_conn_data, fetch_auth_plugin_by_name)(const char * const requested_protocol)
537 {
538 struct st_mysqlnd_authentication_plugin * auth_plugin;
539 char * plugin_name = NULL;
540 DBG_ENTER("mysqlnd_conn_data::fetch_auth_plugin_by_name");
541
542 mnd_sprintf(&plugin_name, 0, "auth_plugin_%s", requested_protocol);
543 DBG_INF_FMT("looking for %s auth plugin", plugin_name);
544 auth_plugin = mysqlnd_plugin_find(plugin_name);
545 mnd_sprintf_free(plugin_name);
546
547 DBG_RETURN(auth_plugin);
548 }
549
550
551
552
553 static enum_func_status
554 mysqlnd_run_authentication(
555 MYSQLND_CONN_DATA * conn,
556 const char * const user,
557 const char * const passwd,
558 const size_t passwd_len,
559 const char * const db,
560 const size_t db_len,
561 const zend_uchar * const auth_plugin_data,
562 const size_t auth_plugin_data_len,
563 const char * const auth_protocol,
564 unsigned int charset_no,
565 const MYSQLND_OPTIONS * const options,
566 zend_ulong mysql_flags,
567 zend_bool silent,
568 zend_bool is_change_user
569 )
570 {
571 enum_func_status ret = FAIL;
572 zend_bool first_call = TRUE;
573
574 char * switch_to_auth_protocol = NULL;
575 size_t switch_to_auth_protocol_len = 0;
576 char * requested_protocol = NULL;
577 zend_uchar * plugin_data;
578 size_t plugin_data_len;
579
580 DBG_ENTER("mysqlnd_run_authentication");
581
582 plugin_data_len = auth_plugin_data_len;
583 plugin_data = mnd_emalloc(plugin_data_len + 1);
584 if (!plugin_data) {
585 goto end;
586 }
587 memcpy(plugin_data, auth_plugin_data, plugin_data_len);
588 plugin_data[plugin_data_len] = '\0';
589
590 requested_protocol = mnd_pestrdup(auth_protocol? auth_protocol : MYSQLND_DEFAULT_AUTH_PROTOCOL, FALSE);
591 if (!requested_protocol) {
592 goto end;
593 }
594
595 do {
596 struct st_mysqlnd_authentication_plugin * auth_plugin = conn->m->fetch_auth_plugin_by_name(requested_protocol);
597
598 if (!auth_plugin) {
599 php_error_docref(NULL, E_WARNING, "The server requested authentication method unknown to the client [%s]", requested_protocol);
600 SET_CLIENT_ERROR(*conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "The server requested authentication method unknown to the client");
601 goto end;
602 }
603 DBG_INF("plugin found");
604
605 {
606 zend_uchar * switch_to_auth_protocol_data = NULL;
607 size_t switch_to_auth_protocol_data_len = 0;
608 zend_uchar * scrambled_data = NULL;
609 size_t scrambled_data_len = 0;
610
611 switch_to_auth_protocol = NULL;
612 switch_to_auth_protocol_len = 0;
613
614 if (conn->auth_plugin_data) {
615 mnd_pefree(conn->auth_plugin_data, conn->persistent);
616 conn->auth_plugin_data = NULL;
617 }
618 conn->auth_plugin_data_len = plugin_data_len;
619 conn->auth_plugin_data = mnd_pemalloc(conn->auth_plugin_data_len, conn->persistent);
620 if (!conn->auth_plugin_data) {
621 SET_OOM_ERROR(*conn->error_info);
622 goto end;
623 }
624 memcpy(conn->auth_plugin_data, plugin_data, plugin_data_len);
625
626 DBG_INF_FMT("salt(%d)=[%.*s]", plugin_data_len, plugin_data_len, plugin_data);
627
628 scrambled_data =
629 auth_plugin->methods.get_auth_data(NULL, &scrambled_data_len, conn, user, passwd, passwd_len,
630 plugin_data, plugin_data_len, options, &conn->net->data->options, mysql_flags);
631 if (conn->error_info->error_no) {
632 goto end;
633 }
634 if (FALSE == is_change_user) {
635 ret = mysqlnd_auth_handshake(conn, user, passwd, passwd_len, db, db_len, options, mysql_flags,
636 charset_no,
637 first_call,
638 requested_protocol,
639 scrambled_data, scrambled_data_len,
640 &switch_to_auth_protocol, &switch_to_auth_protocol_len,
641 &switch_to_auth_protocol_data, &switch_to_auth_protocol_data_len
642 );
643 } else {
644 ret = mysqlnd_auth_change_user(conn, user, strlen(user), passwd, passwd_len, db, db_len, silent,
645 first_call,
646 requested_protocol,
647 scrambled_data, scrambled_data_len,
648 &switch_to_auth_protocol, &switch_to_auth_protocol_len,
649 &switch_to_auth_protocol_data, &switch_to_auth_protocol_data_len
650 );
651 }
652 first_call = FALSE;
653 free(scrambled_data);
654
655 DBG_INF_FMT("switch_to_auth_protocol=%s", switch_to_auth_protocol? switch_to_auth_protocol:"n/a");
656 if (requested_protocol && switch_to_auth_protocol) {
657 mnd_efree(requested_protocol);
658 requested_protocol = switch_to_auth_protocol;
659 }
660
661 if (plugin_data) {
662 mnd_efree(plugin_data);
663 }
664 plugin_data_len = switch_to_auth_protocol_data_len;
665 plugin_data = switch_to_auth_protocol_data;
666 }
667 DBG_INF_FMT("conn->error_info->error_no = %d", conn->error_info->error_no);
668 } while (ret == FAIL && conn->error_info->error_no == 0 && switch_to_auth_protocol != NULL);
669
670 if (ret == PASS) {
671 DBG_INF_FMT("saving requested_protocol=%s", requested_protocol);
672 conn->m->set_client_option(conn, MYSQLND_OPT_AUTH_PROTOCOL, requested_protocol);
673 }
674 end:
675 if (plugin_data) {
676 mnd_efree(plugin_data);
677 }
678 if (requested_protocol) {
679 mnd_efree(requested_protocol);
680 }
681
682 DBG_RETURN(ret);
683 }
684
685
686
687
688 static enum_func_status
689 mysqlnd_connect_run_authentication(
690 MYSQLND_CONN_DATA * conn,
691 const char * const user,
692 const char * const passwd,
693 const char * const db,
694 size_t db_len,
695 size_t passwd_len,
696 const MYSQLND_PACKET_GREET * const greet_packet,
697 const MYSQLND_OPTIONS * const options,
698 zend_ulong mysql_flags
699 )
700 {
701 enum_func_status ret = FAIL;
702 DBG_ENTER("mysqlnd_connect_run_authentication");
703
704 ret = mysqlnd_switch_to_ssl_if_needed(conn, greet_packet, options, mysql_flags);
705 if (PASS == ret) {
706 ret = mysqlnd_run_authentication(conn, user, passwd, passwd_len, db, db_len,
707 greet_packet->auth_plugin_data, greet_packet->auth_plugin_data_len, greet_packet->auth_protocol,
708 greet_packet->charset_no, options, mysql_flags, FALSE , FALSE);
709 }
710 DBG_RETURN(ret);
711 }
712
713
714
715
716 static enum_func_status
717 MYSQLND_METHOD(mysqlnd_conn_data, execute_init_commands)(MYSQLND_CONN_DATA * conn)
718 {
719 enum_func_status ret = PASS;
720
721 DBG_ENTER("mysqlnd_conn_data::execute_init_commands");
722 if (conn->options->init_commands) {
723 unsigned int current_command = 0;
724 for (; current_command < conn->options->num_commands; ++current_command) {
725 const char * const command = conn->options->init_commands[current_command];
726 if (command) {
727 MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_INIT_COMMAND_EXECUTED_COUNT);
728 if (PASS != conn->m->query(conn, command, strlen(command))) {
729 MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_INIT_COMMAND_FAILED_COUNT);
730 ret = FAIL;
731 break;
732 }
733 if (conn->last_query_type == QUERY_SELECT) {
734 MYSQLND_RES * result = conn->m->use_result(conn, 0);
735 if (result) {
736 result->m.free_result(result, TRUE);
737 }
738 }
739 }
740 }
741 }
742 DBG_RETURN(ret);
743 }
744
745
746
747
748 static unsigned int
749 MYSQLND_METHOD(mysqlnd_conn_data, get_updated_connect_flags)(MYSQLND_CONN_DATA * conn, unsigned int mysql_flags)
750 {
751 MYSQLND_NET * net = conn->net;
752
753 DBG_ENTER("mysqlnd_conn_data::get_updated_connect_flags");
754
755 mysql_flags |= MYSQLND_CAPABILITIES;
756
757 mysql_flags |= conn->options->flags;
758
759 #ifndef MYSQLND_COMPRESSION_ENABLED
760 if (mysql_flags & CLIENT_COMPRESS) {
761 mysql_flags &= ~CLIENT_COMPRESS;
762 }
763 #else
764 if (net && net->data->options.flags & MYSQLND_NET_FLAG_USE_COMPRESSION) {
765 mysql_flags |= CLIENT_COMPRESS;
766 }
767 #endif
768 #ifndef MYSQLND_SSL_SUPPORTED
769 if (mysql_flags & CLIENT_SSL) {
770 mysql_flags &= ~CLIENT_SSL;
771 }
772 #else
773 if (net && (net->data->options.ssl_key || net->data->options.ssl_cert ||
774 net->data->options.ssl_ca || net->data->options.ssl_capath || net->data->options.ssl_cipher))
775 {
776 mysql_flags |= CLIENT_SSL;
777 }
778 #endif
779
780 DBG_RETURN(mysql_flags);
781 }
782
783
784
785
786 static enum_func_status
787 MYSQLND_METHOD(mysqlnd_conn_data, connect_handshake)(MYSQLND_CONN_DATA * conn,
788 const char * const host, const char * const user,
789 const char * const passwd, const unsigned int passwd_len,
790 const char * const db, const unsigned int db_len,
791 const unsigned int mysql_flags)
792 {
793 MYSQLND_PACKET_GREET * greet_packet;
794 MYSQLND_NET * net = conn->net;
795
796 DBG_ENTER("mysqlnd_conn_data::connect_handshake");
797
798 greet_packet = conn->protocol->m.get_greet_packet(conn->protocol, FALSE);
799 if (!greet_packet) {
800 SET_OOM_ERROR(*conn->error_info);
801 DBG_RETURN(FAIL);
802 }
803
804 if (FAIL == net->data->m.connect_ex(conn->net, conn->scheme, conn->scheme_len, conn->persistent,
805 conn->stats, conn->error_info))
806 {
807 goto err;
808 }
809
810 DBG_INF_FMT("stream=%p", net->data->m.get_stream(net));
811
812 if (FAIL == PACKET_READ(greet_packet, conn)) {
813 DBG_ERR("Error while reading greeting packet");
814 php_error_docref(NULL, E_WARNING, "Error while reading greeting packet. PID=%d", getpid());
815 goto err;
816 } else if (greet_packet->error_no) {
817 DBG_ERR_FMT("errorno=%u error=%s", greet_packet->error_no, greet_packet->error);
818 SET_CLIENT_ERROR(*conn->error_info, greet_packet->error_no, greet_packet->sqlstate, greet_packet->error);
819 goto err;
820 } else if (greet_packet->pre41) {
821 DBG_ERR_FMT("Connecting to 3.22, 3.23 & 4.0 is not supported. Server is %-.32s", greet_packet->server_version);
822 php_error_docref(NULL, E_WARNING, "Connecting to 3.22, 3.23 & 4.0 "
823 " is not supported. Server is %-.32s", greet_packet->server_version);
824 SET_CLIENT_ERROR(*conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE,
825 "Connecting to 3.22, 3.23 & 4.0 servers is not supported");
826 goto err;
827 }
828
829 conn->thread_id = greet_packet->thread_id;
830 conn->protocol_version = greet_packet->protocol_version;
831 conn->server_version = mnd_pestrdup(greet_packet->server_version, conn->persistent);
832
833 conn->greet_charset = mysqlnd_find_charset_nr(greet_packet->charset_no);
834 if (!conn->greet_charset) {
835 php_error_docref(NULL, E_WARNING,
836 "Server sent charset (%d) unknown to the client. Please, report to the developers", greet_packet->charset_no);
837 SET_CLIENT_ERROR(*conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE,
838 "Server sent charset unknown to the client. Please, report to the developers");
839 goto err;
840 }
841
842 conn->client_flag = mysql_flags;
843 conn->server_capabilities = greet_packet->server_capabilities;
844
845 if (FAIL == mysqlnd_connect_run_authentication(conn, user, passwd, db, db_len, (size_t) passwd_len,
846 greet_packet, conn->options, mysql_flags))
847 {
848 goto err;
849 }
850 memset(conn->upsert_status, 0, sizeof(*conn->upsert_status));
851 conn->upsert_status->warning_count = 0;
852 conn->upsert_status->server_status = greet_packet->server_status;
853 conn->upsert_status->affected_rows = 0;
854
855 PACKET_FREE(greet_packet);
856 DBG_RETURN(PASS);
857 err:
858 conn->client_flag = 0;
859 conn->server_capabilities = 0;
860 PACKET_FREE(greet_packet);
861 DBG_RETURN(FAIL);
862 }
863
864
865
866
867 static enum_func_status
868 MYSQLND_METHOD(mysqlnd_conn_data, connect)(MYSQLND_CONN_DATA * conn,
869 const char *host, const char *user,
870 const char *passwd, unsigned int passwd_len,
871 const char *db, unsigned int db_len,
872 unsigned int port,
873 const char *socket_or_pipe,
874 unsigned int mysql_flags
875 )
876 {
877 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, connect);
878 size_t host_len;
879 zend_bool unix_socket = FALSE;
880 zend_bool named_pipe = FALSE;
881 zend_bool reconnect = FALSE;
882 zend_bool saved_compression = FALSE;
883 zend_bool local_tx_started = FALSE;
884 MYSQLND_NET * net = conn->net;
885
886 DBG_ENTER("mysqlnd_conn_data::connect");
887 DBG_INF_FMT("conn=%p", conn);
888
889 if (PASS != conn->m->local_tx_start(conn, this_func)) {
890 goto err;
891 }
892 local_tx_started = TRUE;
893
894 SET_EMPTY_ERROR(*conn->error_info);
895 SET_ERROR_AFF_ROWS(conn);
896
897 DBG_INF_FMT("host=%s user=%s db=%s port=%u flags=%u persistent=%u state=%u",
898 host?host:"", user?user:"", db?db:"", port, mysql_flags,
899 conn? conn->persistent:0, conn? CONN_GET_STATE(conn):-1);
900
901 if (CONN_GET_STATE(conn) > CONN_ALLOCED && CONN_GET_STATE(conn) ) {
902 DBG_INF("Connecting on a connected handle.");
903
904 if (CONN_GET_STATE(conn) < CONN_QUIT_SENT) {
905 MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CLOSE_IMPLICIT);
906 reconnect = TRUE;
907 conn->m->send_close(conn);
908 }
909
910 conn->m->free_contents(conn);
911 MYSQLND_DEC_CONN_STATISTIC(conn->stats, STAT_OPENED_CONNECTIONS);
912 if (conn->persistent) {
913 MYSQLND_DEC_CONN_STATISTIC(conn->stats, STAT_OPENED_PERSISTENT_CONNECTIONS);
914 }
915
916 if (net->data->compressed) {
917
918
919
920
921
922 saved_compression = TRUE;
923 net->data->compressed = FALSE;
924 }
925 if (net->data->ssl) {
926 net->data->ssl = FALSE;
927 }
928 } else {
929 unsigned int max_allowed_size = MYSQLND_ASSEMBLED_PACKET_MAX_SIZE;
930 conn->m->set_client_option(conn, MYSQLND_OPT_MAX_ALLOWED_PACKET, (char *)&max_allowed_size);
931 }
932
933 if (!host || !host[0]) {
934 host = "localhost";
935 }
936 if (!user) {
937 DBG_INF_FMT("no user given, using empty string");
938 user = "";
939 }
940 if (!passwd) {
941 DBG_INF_FMT("no password given, using empty string");
942 passwd = "";
943 passwd_len = 0;
944 }
945 if (!db) {
946 DBG_INF_FMT("no db given, using empty string");
947 db = "";
948 db_len = 0;
949 } else {
950 mysql_flags |= CLIENT_CONNECT_WITH_DB;
951 }
952
953 host_len = strlen(host);
954 {
955 char * transport = NULL;
956 int transport_len;
957 #ifndef PHP_WIN32
958 if (host_len == sizeof("localhost") - 1 && !strncasecmp(host, "localhost", host_len)) {
959 DBG_INF_FMT("socket=%s", socket_or_pipe? socket_or_pipe:"n/a");
960 if (!socket_or_pipe) {
961 socket_or_pipe = "/tmp/mysql.sock";
962 }
963 transport_len = mnd_sprintf(&transport, 0, "unix://%s", socket_or_pipe);
964 unix_socket = TRUE;
965 #else
966 if (host_len == sizeof(".") - 1 && host[0] == '.') {
967
968 if (!socket_or_pipe) {
969 socket_or_pipe = "\\\\.\\pipe\\MySQL";
970 }
971 transport_len = mnd_sprintf(&transport, 0, "pipe://%s", socket_or_pipe);
972 named_pipe = TRUE;
973 #endif
974 } else {
975 if (!port) {
976 port = 3306;
977 }
978 transport_len = mnd_sprintf(&transport, 0, "tcp://%s:%u", host, port);
979 }
980 if (!transport) {
981 SET_OOM_ERROR(*conn->error_info);
982 goto err;
983 }
984 DBG_INF_FMT("transport=%s conn->scheme=%s", transport, conn->scheme);
985 conn->scheme = mnd_pestrndup(transport, transport_len, conn->persistent);
986 conn->scheme_len = transport_len;
987 mnd_sprintf_free(transport);
988 transport = NULL;
989 if (!conn->scheme) {
990 goto err;
991 }
992 }
993
994 mysql_flags = conn->m->get_updated_connect_flags(conn, mysql_flags);
995
996 if (FAIL == conn->m->connect_handshake(conn, host, user, passwd, passwd_len, db, db_len, mysql_flags)) {
997 goto err;
998 }
999
1000 {
1001 CONN_SET_STATE(conn, CONN_READY);
1002
1003 if (saved_compression) {
1004 net->data->compressed = TRUE;
1005 }
1006
1007
1008
1009
1010
1011 net->data->compressed = mysql_flags & CLIENT_COMPRESS? TRUE:FALSE;
1012
1013 conn->user_len = strlen(user);
1014 conn->user = mnd_pestrndup(user, conn->user_len, conn->persistent);
1015 conn->passwd = mnd_pestrndup(passwd, passwd_len, conn->persistent);
1016 conn->passwd_len = passwd_len;
1017 conn->port = port;
1018 conn->connect_or_select_db = mnd_pestrndup(db, db_len, conn->persistent);
1019 conn->connect_or_select_db_len = db_len;
1020
1021 if (!conn->user || !conn->passwd || !conn->connect_or_select_db) {
1022 SET_OOM_ERROR(*conn->error_info);
1023 goto err;
1024 }
1025
1026 if (!unix_socket && !named_pipe) {
1027 conn->host = mnd_pestrndup(host, host_len, conn->persistent);
1028 if (!conn->host) {
1029 SET_OOM_ERROR(*conn->error_info);
1030 goto err;
1031 }
1032 conn->host_len = host_len;
1033 {
1034 char *p;
1035 mnd_sprintf(&p, 0, "%s via TCP/IP", conn->host);
1036 if (!p) {
1037 SET_OOM_ERROR(*conn->error_info);
1038 goto err;
1039 }
1040 conn->host_info = mnd_pestrdup(p, conn->persistent);
1041 mnd_sprintf_free(p);
1042 if (!conn->host_info) {
1043 SET_OOM_ERROR(*conn->error_info);
1044 goto err;
1045 }
1046 }
1047 } else {
1048 conn->unix_socket = mnd_pestrdup(socket_or_pipe, conn->persistent);
1049 if (unix_socket) {
1050 conn->host_info = mnd_pestrdup("Localhost via UNIX socket", conn->persistent);
1051 } else if (named_pipe) {
1052 char *p;
1053 mnd_sprintf(&p, 0, "%s via named pipe", conn->unix_socket);
1054 if (!p) {
1055 SET_OOM_ERROR(*conn->error_info);
1056 goto err;
1057 }
1058 conn->host_info = mnd_pestrdup(p, conn->persistent);
1059 mnd_sprintf_free(p);
1060 if (!conn->host_info) {
1061 SET_OOM_ERROR(*conn->error_info);
1062 goto err;
1063 }
1064 } else {
1065 php_error_docref(NULL, E_WARNING, "Impossible. Should be either socket or a pipe. Report a bug!");
1066 }
1067 if (!conn->unix_socket || !conn->host_info) {
1068 SET_OOM_ERROR(*conn->error_info);
1069 goto err;
1070 }
1071 conn->unix_socket_len = strlen(conn->unix_socket);
1072 }
1073 conn->max_packet_size = MYSQLND_ASSEMBLED_PACKET_MAX_SIZE;
1074
1075
1076 SET_EMPTY_ERROR(*conn->error_info);
1077
1078 mysqlnd_local_infile_default(conn);
1079
1080 if (FAIL == conn->m->execute_init_commands(conn)) {
1081 goto err;
1082 }
1083
1084 MYSQLND_INC_CONN_STATISTIC_W_VALUE2(conn->stats, STAT_CONNECT_SUCCESS, 1, STAT_OPENED_CONNECTIONS, 1);
1085 if (reconnect) {
1086 MYSQLND_INC_GLOBAL_STATISTIC(STAT_RECONNECT);
1087 }
1088 if (conn->persistent) {
1089 MYSQLND_INC_CONN_STATISTIC_W_VALUE2(conn->stats, STAT_PCONNECT_SUCCESS, 1, STAT_OPENED_PERSISTENT_CONNECTIONS, 1);
1090 }
1091
1092 DBG_INF_FMT("connection_id=%llu", conn->thread_id);
1093
1094 conn->m->local_tx_end(conn, this_func, PASS);
1095 DBG_RETURN(PASS);
1096 }
1097 err:
1098
1099 DBG_ERR_FMT("[%u] %.128s (trying to connect via %s)", conn->error_info->error_no, conn->error_info->error, conn->scheme);
1100 if (!conn->error_info->error_no) {
1101 SET_CLIENT_ERROR(*conn->error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, conn->error_info->error? conn->error_info->error:"Unknown error");
1102 php_error_docref(NULL, E_WARNING, "[%u] %.128s (trying to connect via %s)",
1103 conn->error_info->error_no, conn->error_info->error, conn->scheme);
1104 }
1105
1106 conn->m->free_contents(conn);
1107 MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CONNECT_FAILURE);
1108 if (TRUE == local_tx_started) {
1109 conn->m->local_tx_end(conn, this_func, FAIL);
1110 }
1111
1112 DBG_RETURN(FAIL);
1113 }
1114
1115
1116
1117
1118 static enum_func_status
1119 MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn_handle,
1120 const char * host, const char * user,
1121 const char * passwd, unsigned int passwd_len,
1122 const char * db, unsigned int db_len,
1123 unsigned int port,
1124 const char * socket_or_pipe,
1125 unsigned int mysql_flags
1126 )
1127 {
1128 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, connect);
1129 enum_func_status ret = FAIL;
1130 MYSQLND_CONN_DATA * conn = conn_handle->data;
1131
1132 DBG_ENTER("mysqlnd_conn::connect");
1133
1134 if (PASS == conn->m->local_tx_start(conn, this_func)) {
1135 mysqlnd_options4(conn_handle, MYSQL_OPT_CONNECT_ATTR_ADD, "_client_name", "mysqlnd");
1136 ret = conn->m->connect(conn, host, user, passwd, passwd_len, db, db_len, port, socket_or_pipe, mysql_flags);
1137
1138 conn->m->local_tx_end(conn, this_func, FAIL);
1139 }
1140 DBG_RETURN(ret);
1141 }
1142
1143
1144
1145
1146 PHPAPI MYSQLND * mysqlnd_connect(MYSQLND * conn_handle,
1147 const char * host, const char * user,
1148 const char * passwd, unsigned int passwd_len,
1149 const char * db, unsigned int db_len,
1150 unsigned int port,
1151 const char * socket_or_pipe,
1152 unsigned int mysql_flags,
1153 unsigned int client_api_flags
1154 )
1155 {
1156 enum_func_status ret = FAIL;
1157 zend_bool self_alloced = FALSE;
1158
1159 DBG_ENTER("mysqlnd_connect");
1160 DBG_INF_FMT("host=%s user=%s db=%s port=%u flags=%u", host?host:"", user?user:"", db?db:"", port, mysql_flags);
1161
1162 if (!conn_handle) {
1163 self_alloced = TRUE;
1164 if (!(conn_handle = mysqlnd_init(client_api_flags, FALSE))) {
1165
1166 DBG_RETURN(NULL);
1167 }
1168 }
1169
1170 ret = conn_handle->m->connect(conn_handle, host, user, passwd, passwd_len, db, db_len, port, socket_or_pipe, mysql_flags);
1171
1172 if (ret == FAIL) {
1173 if (self_alloced) {
1174
1175
1176
1177
1178 conn_handle->m->dtor(conn_handle);
1179 }
1180 DBG_RETURN(NULL);
1181 }
1182 DBG_RETURN(conn_handle);
1183 }
1184
1185
1186
1187
1188
1189
1190
1191
1192 static enum_func_status
1193 MYSQLND_METHOD(mysqlnd_conn_data, query)(MYSQLND_CONN_DATA * conn, const char * query, unsigned int query_len)
1194 {
1195 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, query);
1196 enum_func_status ret = FAIL;
1197 DBG_ENTER("mysqlnd_conn_data::query");
1198 DBG_INF_FMT("conn=%p conn=%llu query=%s", conn, conn->thread_id, query);
1199
1200 if (PASS == conn->m->local_tx_start(conn, this_func)) {
1201 if (PASS == conn->m->send_query(conn, query, query_len, MYSQLND_SEND_QUERY_IMPLICIT, NULL, NULL) &&
1202 PASS == conn->m->reap_query(conn, MYSQLND_REAP_RESULT_IMPLICIT))
1203 {
1204 ret = PASS;
1205 if (conn->last_query_type == QUERY_UPSERT && conn->upsert_status->affected_rows) {
1206 MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn->stats, STAT_ROWS_AFFECTED_NORMAL, conn->upsert_status->affected_rows);
1207 }
1208 }
1209 conn->m->local_tx_end(conn, this_func, ret);
1210 }
1211 DBG_RETURN(ret);
1212 }
1213
1214
1215
1216
1217 static enum_func_status
1218 MYSQLND_METHOD(mysqlnd_conn_data, send_query)(MYSQLND_CONN_DATA * conn, const char * query, unsigned int query_len,
1219 enum_mysqlnd_send_query_type type, zval *read_cb, zval *err_cb)
1220 {
1221 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, send_query);
1222 enum_func_status ret = FAIL;
1223 DBG_ENTER("mysqlnd_conn_data::send_query");
1224 DBG_INF_FMT("conn=%llu query=%s", conn->thread_id, query);
1225 DBG_INF_FMT("conn->server_status=%u", conn->upsert_status->server_status);
1226
1227 if (PASS == conn->m->local_tx_start(conn, this_func)) {
1228 ret = conn->m->simple_command(conn, COM_QUERY, (zend_uchar *) query, query_len,
1229 PROT_LAST ,
1230 FALSE, FALSE);
1231 if (PASS == ret) {
1232 CONN_SET_STATE(conn, CONN_QUERY_SENT);
1233 }
1234 conn->m->local_tx_end(conn, this_func, ret);
1235 }
1236 DBG_INF_FMT("conn->server_status=%u", conn->upsert_status->server_status);
1237 DBG_RETURN(ret);
1238 }
1239
1240
1241
1242
1243 static enum_func_status
1244 MYSQLND_METHOD(mysqlnd_conn_data, reap_query)(MYSQLND_CONN_DATA * conn, enum_mysqlnd_reap_result_type type)
1245 {
1246 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, reap_query);
1247 enum_mysqlnd_connection_state state = CONN_GET_STATE(conn);
1248 enum_func_status ret = FAIL;
1249 DBG_ENTER("mysqlnd_conn_data::reap_query");
1250 DBG_INF_FMT("conn=%llu", conn->thread_id);
1251
1252 DBG_INF_FMT("conn->server_status=%u", conn->upsert_status->server_status);
1253 if (PASS == conn->m->local_tx_start(conn, this_func)) {
1254 if (state <= CONN_READY || state == CONN_QUIT_SENT) {
1255 php_error_docref(NULL, E_WARNING, "Connection not opened, clear or has been closed");
1256 DBG_ERR_FMT("Connection not opened, clear or has been closed. State=%u", state);
1257 DBG_RETURN(ret);
1258 }
1259 ret = conn->m->query_read_result_set_header(conn, NULL);
1260
1261 conn->m->local_tx_end(conn, this_func, ret);
1262 }
1263 DBG_INF_FMT("conn->server_status=%u", conn->upsert_status->server_status);
1264 DBG_RETURN(ret);
1265 }
1266
1267
1268
1269 #include "php_network.h"
1270
1271
1272 MYSQLND ** mysqlnd_stream_array_check_for_readiness(MYSQLND ** conn_array)
1273 {
1274 int cnt = 0;
1275 MYSQLND **p = conn_array, **p_p;
1276 MYSQLND **ret = NULL;
1277
1278 while (*p) {
1279 if (CONN_GET_STATE((*p)->data) <= CONN_READY || CONN_GET_STATE((*p)->data) == CONN_QUIT_SENT) {
1280 cnt++;
1281 }
1282 p++;
1283 }
1284 if (cnt) {
1285 MYSQLND **ret_p = ret = ecalloc(cnt + 1, sizeof(MYSQLND *));
1286 p_p = p = conn_array;
1287 while (*p) {
1288 if (CONN_GET_STATE((*p)->data) <= CONN_READY || CONN_GET_STATE((*p)->data) == CONN_QUIT_SENT) {
1289 *ret_p = *p;
1290 *p = NULL;
1291 ret_p++;
1292 } else {
1293 *p_p = *p;
1294 p_p++;
1295 }
1296 p++;
1297 }
1298 *ret_p = NULL;
1299 }
1300 return ret;
1301 }
1302
1303
1304
1305
1306 static int mysqlnd_stream_array_to_fd_set(MYSQLND ** conn_array, fd_set * fds, php_socket_t * max_fd)
1307 {
1308 php_socket_t this_fd;
1309 php_stream *stream = NULL;
1310 unsigned int cnt = 0;
1311 MYSQLND **p = conn_array;
1312 DBG_ENTER("mysqlnd_stream_array_to_fd_set");
1313
1314 while (*p) {
1315
1316
1317
1318
1319
1320 stream = (*p)->data->net->data->m.get_stream((*p)->data->net);
1321 DBG_INF_FMT("conn=%llu stream=%p", (*p)->data->thread_id, stream);
1322 if (stream != NULL && SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL,
1323 (void*)&this_fd, 1) && ZEND_VALID_SOCKET(this_fd)) {
1324
1325 PHP_SAFE_FD_SET(this_fd, fds);
1326
1327 if (this_fd > *max_fd) {
1328 *max_fd = this_fd;
1329 }
1330 cnt++;
1331 }
1332 p++;
1333 }
1334 DBG_RETURN(cnt ? 1 : 0);
1335 }
1336
1337
1338
1339
1340 static int mysqlnd_stream_array_from_fd_set(MYSQLND ** conn_array, fd_set * fds)
1341 {
1342 php_socket_t this_fd;
1343 php_stream *stream = NULL;
1344 int ret = 0;
1345 zend_bool disproportion = FALSE;
1346 MYSQLND **fwd = conn_array, **bckwd = conn_array;
1347 DBG_ENTER("mysqlnd_stream_array_from_fd_set");
1348
1349 while (*fwd) {
1350 stream = (*fwd)->data->net->data->m.get_stream((*fwd)->data->net);
1351 DBG_INF_FMT("conn=%llu stream=%p", (*fwd)->data->thread_id, stream);
1352 if (stream != NULL && SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL,
1353 (void*)&this_fd, 1) && ZEND_VALID_SOCKET(this_fd)) {
1354 if (PHP_SAFE_FD_ISSET(this_fd, fds)) {
1355 if (disproportion) {
1356 *bckwd = *fwd;
1357 }
1358 bckwd++;
1359 fwd++;
1360 ret++;
1361 continue;
1362 }
1363 }
1364 disproportion = TRUE;
1365 fwd++;
1366 }
1367 *bckwd = NULL;
1368
1369 DBG_RETURN(ret);
1370 }
1371
1372
1373
1374 #ifndef PHP_WIN32
1375 #define php_select(m, r, w, e, t) select(m, r, w, e, t)
1376 #else
1377 #include "win32/select.h"
1378 #endif
1379
1380
1381
1382 PHPAPI enum_func_status
1383 mysqlnd_poll(MYSQLND **r_array, MYSQLND **e_array, MYSQLND ***dont_poll, long sec, long usec, int * desc_num)
1384 {
1385 struct timeval tv;
1386 struct timeval *tv_p = NULL;
1387 fd_set rfds, wfds, efds;
1388 php_socket_t max_fd = 0;
1389 int retval, sets = 0;
1390 int set_count, max_set_count = 0;
1391
1392 DBG_ENTER("_mysqlnd_poll");
1393 if (sec < 0 || usec < 0) {
1394 php_error_docref(NULL, E_WARNING, "Negative values passed for sec and/or usec");
1395 DBG_RETURN(FAIL);
1396 }
1397
1398 FD_ZERO(&rfds);
1399 FD_ZERO(&wfds);
1400 FD_ZERO(&efds);
1401
1402 if (r_array != NULL) {
1403 *dont_poll = mysqlnd_stream_array_check_for_readiness(r_array);
1404 set_count = mysqlnd_stream_array_to_fd_set(r_array, &rfds, &max_fd);
1405 if (set_count > max_set_count) {
1406 max_set_count = set_count;
1407 }
1408 sets += set_count;
1409 }
1410
1411 if (e_array != NULL) {
1412 set_count = mysqlnd_stream_array_to_fd_set(e_array, &efds, &max_fd);
1413 if (set_count > max_set_count) {
1414 max_set_count = set_count;
1415 }
1416 sets += set_count;
1417 }
1418
1419 if (!sets) {
1420 php_error_docref(NULL, E_WARNING, *dont_poll ? "All arrays passed are clear":"No stream arrays were passed");
1421 DBG_ERR_FMT(*dont_poll ? "All arrays passed are clear":"No stream arrays were passed");
1422 DBG_RETURN(FAIL);
1423 }
1424
1425 PHP_SAFE_MAX_FD(max_fd, max_set_count);
1426
1427
1428 if (usec > 999999) {
1429 tv.tv_sec = sec + (usec / 1000000);
1430 tv.tv_usec = usec % 1000000;
1431 } else {
1432 tv.tv_sec = sec;
1433 tv.tv_usec = usec;
1434 }
1435
1436 tv_p = &tv;
1437
1438 retval = php_select(max_fd + 1, &rfds, &wfds, &efds, tv_p);
1439
1440 if (retval == -1) {
1441 php_error_docref(NULL, E_WARNING, "unable to select [%d]: %s (max_fd=%d)",
1442 errno, strerror(errno), max_fd);
1443 DBG_RETURN(FAIL);
1444 }
1445
1446 if (r_array != NULL) {
1447 mysqlnd_stream_array_from_fd_set(r_array, &rfds);
1448 }
1449 if (e_array != NULL) {
1450 mysqlnd_stream_array_from_fd_set(e_array, &efds);
1451 }
1452
1453 *desc_num = retval;
1454 DBG_RETURN(PASS);
1455 }
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467 MYSQLND_RES *
1468 MYSQLND_METHOD(mysqlnd_conn_data, list_fields)(MYSQLND_CONN_DATA * conn, const char *table, const char *achtung_wild)
1469 {
1470 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, list_fields);
1471
1472 zend_uchar buff[MYSQLND_MAX_ALLOWED_DB_LEN * 2 + 1 + 1], *p;
1473 size_t table_len, wild_len;
1474 MYSQLND_RES * result = NULL;
1475 DBG_ENTER("mysqlnd_conn_data::list_fields");
1476 DBG_INF_FMT("conn=%llu table=%s wild=%s", conn->thread_id, table? table:"",achtung_wild? achtung_wild:"");
1477
1478 if (PASS == conn->m->local_tx_start(conn, this_func)) {
1479 do {
1480 p = buff;
1481 if (table && (table_len = strlen(table))) {
1482 size_t to_copy = MIN(table_len, MYSQLND_MAX_ALLOWED_DB_LEN);
1483 memcpy(p, table, to_copy);
1484 p += to_copy;
1485 *p++ = '\0';
1486 }
1487
1488 if (achtung_wild && (wild_len = strlen(achtung_wild))) {
1489 size_t to_copy = MIN(wild_len, MYSQLND_MAX_ALLOWED_DB_LEN);
1490 memcpy(p, achtung_wild, to_copy);
1491 p += to_copy;
1492 *p++ = '\0';
1493 }
1494
1495 if (PASS != conn->m->simple_command(conn, COM_FIELD_LIST, buff, p - buff,
1496 PROT_LAST ,
1497 FALSE, TRUE)) {
1498 conn->m->local_tx_end(conn, 0, FAIL);
1499 break;
1500 }
1501
1502
1503
1504
1505
1506 result = conn->m->result_init(5000, conn->persistent);
1507 if (!result) {
1508 break;
1509 }
1510
1511 if (FAIL == result->m.read_result_metadata(result, conn)) {
1512 DBG_ERR("Error occurred while reading metadata");
1513 result->m.free_result(result, TRUE);
1514 result = NULL;
1515 break;
1516 }
1517
1518 result->type = MYSQLND_RES_NORMAL;
1519 result->unbuf = mysqlnd_result_unbuffered_init(result->field_count, FALSE, result->persistent);
1520 if (!result->unbuf) {
1521
1522 SET_OOM_ERROR(*conn->error_info);
1523 result->m.free_result(result, TRUE);
1524 result = NULL;
1525 break;
1526 }
1527 result->unbuf->eof_reached = TRUE;
1528 } while (0);
1529 conn->m->local_tx_end(conn, this_func, result == NULL? FAIL:PASS);
1530 }
1531
1532 DBG_RETURN(result);
1533 }
1534
1535
1536
1537
1538 MYSQLND_RES *
1539 MYSQLND_METHOD(mysqlnd_conn_data, list_method)(MYSQLND_CONN_DATA * conn, const char * query, const char *achtung_wild, char *par1)
1540 {
1541 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, list_method);
1542 char * show_query = NULL;
1543 size_t show_query_len;
1544 MYSQLND_RES * result = NULL;
1545
1546 DBG_ENTER("mysqlnd_conn_data::list_method");
1547 DBG_INF_FMT("conn=%llu query=%s wild=%u", conn->thread_id, query, achtung_wild);
1548
1549 if (PASS == conn->m->local_tx_start(conn, this_func)) {
1550 if (par1) {
1551 if (achtung_wild) {
1552 show_query_len = mnd_sprintf(&show_query, 0, query, par1, achtung_wild);
1553 } else {
1554 show_query_len = mnd_sprintf(&show_query, 0, query, par1);
1555 }
1556 } else {
1557 if (achtung_wild) {
1558 show_query_len = mnd_sprintf(&show_query, 0, query, achtung_wild);
1559 } else {
1560 show_query_len = strlen(show_query = (char *)query);
1561 }
1562 }
1563
1564 if (PASS == conn->m->query(conn, show_query, show_query_len)) {
1565 result = conn->m->store_result(conn, MYSQLND_STORE_NO_COPY);
1566 }
1567 if (show_query != query) {
1568 mnd_sprintf_free(show_query);
1569 }
1570 conn->m->local_tx_end(conn, this_func, result == NULL? FAIL:PASS);
1571 }
1572 DBG_RETURN(result);
1573 }
1574
1575
1576
1577
1578 static unsigned int
1579 MYSQLND_METHOD(mysqlnd_conn_data, errno)(const MYSQLND_CONN_DATA * const conn)
1580 {
1581 return conn->error_info->error_no;
1582 }
1583
1584
1585
1586
1587 static const char *
1588 MYSQLND_METHOD(mysqlnd_conn_data, error)(const MYSQLND_CONN_DATA * const conn)
1589 {
1590 return conn->error_info->error;
1591 }
1592
1593
1594
1595
1596 static const char *
1597 MYSQLND_METHOD(mysqlnd_conn_data, sqlstate)(const MYSQLND_CONN_DATA * const conn)
1598 {
1599 return conn->error_info->sqlstate[0] ? conn->error_info->sqlstate:MYSQLND_SQLSTATE_NULL;
1600 }
1601
1602
1603
1604
1605 PHPAPI zend_ulong
1606 mysqlnd_old_escape_string(char * newstr, const char * escapestr, size_t escapestr_len)
1607 {
1608 DBG_ENTER("mysqlnd_old_escape_string");
1609 DBG_RETURN(mysqlnd_cset_escape_slashes(mysqlnd_find_charset_name("latin1"), newstr, escapestr, escapestr_len));
1610 }
1611
1612
1613
1614
1615 static enum_func_status
1616 MYSQLND_METHOD(mysqlnd_conn_data, ssl_set)(MYSQLND_CONN_DATA * const conn, const char * key, const char * const cert,
1617 const char * const ca, const char * const capath, const char * const cipher)
1618 {
1619 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, ssl_set);
1620 enum_func_status ret = FAIL;
1621 MYSQLND_NET * net = conn->net;
1622 DBG_ENTER("mysqlnd_conn_data::ssl_set");
1623
1624 if (PASS == conn->m->local_tx_start(conn, this_func)) {
1625 ret = (PASS == net->data->m.set_client_option(net, MYSQLND_OPT_SSL_KEY, key) &&
1626 PASS == net->data->m.set_client_option(net, MYSQLND_OPT_SSL_CERT, cert) &&
1627 PASS == net->data->m.set_client_option(net, MYSQLND_OPT_SSL_CA, ca) &&
1628 PASS == net->data->m.set_client_option(net, MYSQLND_OPT_SSL_CAPATH, capath) &&
1629 PASS == net->data->m.set_client_option(net, MYSQLND_OPT_SSL_CIPHER, cipher)) ? PASS : FAIL;
1630
1631 conn->m->local_tx_end(conn, this_func, ret);
1632 }
1633 DBG_RETURN(ret);
1634 }
1635
1636
1637
1638
1639 static zend_ulong
1640 MYSQLND_METHOD(mysqlnd_conn_data, escape_string)(MYSQLND_CONN_DATA * const conn, char * newstr, const char * escapestr, size_t escapestr_len)
1641 {
1642 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, escape_string);
1643 zend_ulong ret = FAIL;
1644 DBG_ENTER("mysqlnd_conn_data::escape_string");
1645 DBG_INF_FMT("conn=%llu", conn->thread_id);
1646
1647 if (PASS == conn->m->local_tx_start(conn, this_func)) {
1648 DBG_INF_FMT("server_status=%u", conn->upsert_status->server_status);
1649 if (conn->upsert_status->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES) {
1650 ret = mysqlnd_cset_escape_quotes(conn->charset, newstr, escapestr, escapestr_len);
1651 } else {
1652 ret = mysqlnd_cset_escape_slashes(conn->charset, newstr, escapestr, escapestr_len);
1653 }
1654 conn->m->local_tx_end(conn, this_func, PASS);
1655 }
1656 DBG_RETURN(ret);
1657 }
1658
1659
1660
1661
1662 static enum_func_status
1663 MYSQLND_METHOD(mysqlnd_conn_data, dump_debug_info)(MYSQLND_CONN_DATA * const conn)
1664 {
1665 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, server_dump_debug_information);
1666 enum_func_status ret = FAIL;
1667 DBG_ENTER("mysqlnd_conn_data::dump_debug_info");
1668 DBG_INF_FMT("conn=%llu", conn->thread_id);
1669 if (PASS == conn->m->local_tx_start(conn, this_func)) {
1670 ret = conn->m->simple_command(conn, COM_DEBUG, NULL, 0, PROT_EOF_PACKET, FALSE, TRUE);
1671
1672 conn->m->local_tx_end(conn, this_func, ret);
1673 }
1674
1675 DBG_RETURN(ret);
1676 }
1677
1678
1679
1680
1681 static enum_func_status
1682 MYSQLND_METHOD(mysqlnd_conn_data, select_db)(MYSQLND_CONN_DATA * const conn, const char * const db, unsigned int db_len)
1683 {
1684 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, select_db);
1685 enum_func_status ret = FAIL;
1686
1687 DBG_ENTER("mysqlnd_conn_data::select_db");
1688 DBG_INF_FMT("conn=%llu db=%s", conn->thread_id, db);
1689
1690 if (PASS == conn->m->local_tx_start(conn, this_func)) {
1691 ret = conn->m->simple_command(conn, COM_INIT_DB, (zend_uchar*) db, db_len, PROT_OK_PACKET, FALSE, TRUE);
1692
1693
1694
1695
1696 SET_ERROR_AFF_ROWS(conn);
1697 if (ret == PASS) {
1698 if (conn->connect_or_select_db) {
1699 mnd_pefree(conn->connect_or_select_db, conn->persistent);
1700 }
1701 conn->connect_or_select_db = mnd_pestrndup(db, db_len, conn->persistent);
1702 conn->connect_or_select_db_len = db_len;
1703 if (!conn->connect_or_select_db) {
1704
1705 SET_OOM_ERROR(*conn->error_info);
1706 ret = FAIL;
1707 }
1708 }
1709 conn->m->local_tx_end(conn, this_func, ret);
1710 }
1711 DBG_RETURN(ret);
1712 }
1713
1714
1715
1716
1717 static enum_func_status
1718 MYSQLND_METHOD(mysqlnd_conn_data, ping)(MYSQLND_CONN_DATA * const conn)
1719 {
1720 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, ping);
1721 enum_func_status ret = FAIL;
1722
1723 DBG_ENTER("mysqlnd_conn_data::ping");
1724 DBG_INF_FMT("conn=%llu", conn->thread_id);
1725
1726 if (PASS == conn->m->local_tx_start(conn, this_func)) {
1727 ret = conn->m->simple_command(conn, COM_PING, NULL, 0, PROT_OK_PACKET, TRUE, TRUE);
1728
1729
1730
1731
1732 SET_ERROR_AFF_ROWS(conn);
1733
1734 conn->m->local_tx_end(conn, this_func, ret);
1735 }
1736 DBG_INF_FMT("ret=%u", ret);
1737 DBG_RETURN(ret);
1738 }
1739
1740
1741
1742
1743 static enum_func_status
1744 MYSQLND_METHOD(mysqlnd_conn_data, statistic)(MYSQLND_CONN_DATA * conn, zend_string **message)
1745 {
1746 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, get_server_statistics);
1747 enum_func_status ret = FAIL;
1748 MYSQLND_PACKET_STATS * stats_header;
1749
1750 DBG_ENTER("mysqlnd_conn_data::statistic");
1751 DBG_INF_FMT("conn=%llu", conn->thread_id);
1752
1753 if (PASS == conn->m->local_tx_start(conn, this_func)) {
1754 do {
1755 ret = conn->m->simple_command(conn, COM_STATISTICS, NULL, 0, PROT_LAST, FALSE, TRUE);
1756 if (FAIL == ret) {
1757 break;
1758 }
1759 stats_header = conn->protocol->m.get_stats_packet(conn->protocol, FALSE);
1760 if (!stats_header) {
1761 SET_OOM_ERROR(*conn->error_info);
1762 break;
1763 }
1764
1765 if (PASS == (ret = PACKET_READ(stats_header, conn))) {
1766
1767 *message = zend_string_init(stats_header->message, stats_header->message_len, 0);
1768 DBG_INF(ZSTR_VAL(*message));
1769 }
1770 PACKET_FREE(stats_header);
1771 } while (0);
1772
1773 conn->m->local_tx_end(conn, this_func, ret);
1774 }
1775 DBG_RETURN(ret);
1776 }
1777
1778
1779
1780
1781 static enum_func_status
1782 MYSQLND_METHOD(mysqlnd_conn_data, kill)(MYSQLND_CONN_DATA * conn, unsigned int pid)
1783 {
1784 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, kill_connection);
1785 enum_func_status ret = FAIL;
1786 zend_uchar buff[4];
1787
1788 DBG_ENTER("mysqlnd_conn_data::kill");
1789 DBG_INF_FMT("conn=%llu pid=%u", conn->thread_id, pid);
1790
1791 if (PASS == conn->m->local_tx_start(conn, this_func)) {
1792 int4store(buff, pid);
1793
1794
1795 if (pid != conn->thread_id) {
1796 ret = conn->m->simple_command(conn, COM_PROCESS_KILL, buff, 4, PROT_OK_PACKET, FALSE, TRUE);
1797
1798
1799
1800
1801 SET_ERROR_AFF_ROWS(conn);
1802 } else if (PASS == (ret = conn->m->simple_command(conn, COM_PROCESS_KILL, buff, 4, PROT_LAST, FALSE, TRUE))) {
1803 CONN_SET_STATE(conn, CONN_QUIT_SENT);
1804 conn->m->send_close(conn);
1805 }
1806
1807 conn->m->local_tx_end(conn, this_func, ret);
1808 }
1809 DBG_RETURN(ret);
1810 }
1811
1812
1813
1814
1815 static enum_func_status
1816 MYSQLND_METHOD(mysqlnd_conn_data, set_charset)(MYSQLND_CONN_DATA * const conn, const char * const csname)
1817 {
1818 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, set_charset);
1819 enum_func_status ret = FAIL;
1820 const MYSQLND_CHARSET * const charset = mysqlnd_find_charset_name(csname);
1821
1822 DBG_ENTER("mysqlnd_conn_data::set_charset");
1823 DBG_INF_FMT("conn=%llu cs=%s", conn->thread_id, csname);
1824
1825 if (!charset) {
1826 SET_CLIENT_ERROR(*conn->error_info, CR_CANT_FIND_CHARSET, UNKNOWN_SQLSTATE,
1827 "Invalid characterset or character set not supported");
1828 DBG_RETURN(ret);
1829 }
1830
1831 if (PASS == conn->m->local_tx_start(conn, this_func)) {
1832 char * query;
1833 size_t query_len = mnd_sprintf(&query, 0, "SET NAMES %s", csname);
1834
1835 if (FAIL == (ret = conn->m->query(conn, query, query_len))) {
1836 php_error_docref(NULL, E_WARNING, "Error executing query");
1837 } else if (conn->error_info->error_no) {
1838 ret = FAIL;
1839 } else {
1840 conn->charset = charset;
1841 }
1842 mnd_sprintf_free(query);
1843
1844 conn->m->local_tx_end(conn, this_func, ret);
1845 }
1846
1847 DBG_INF(ret == PASS? "PASS":"FAIL");
1848 DBG_RETURN(ret);
1849 }
1850
1851
1852
1853
1854 static enum_func_status
1855 MYSQLND_METHOD(mysqlnd_conn_data, refresh)(MYSQLND_CONN_DATA * const conn, uint8_t options)
1856 {
1857 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, refresh_server);
1858 enum_func_status ret = FAIL;
1859 zend_uchar bits[1];
1860 DBG_ENTER("mysqlnd_conn_data::refresh");
1861 DBG_INF_FMT("conn=%llu options=%lu", conn->thread_id, options);
1862
1863 if (PASS == conn->m->local_tx_start(conn, this_func)) {
1864 int1store(bits, options);
1865
1866 ret = conn->m->simple_command(conn, COM_REFRESH, bits, 1, PROT_OK_PACKET, FALSE, TRUE);
1867
1868 conn->m->local_tx_end(conn, this_func, ret);
1869 }
1870 DBG_RETURN(ret);
1871 }
1872
1873
1874
1875
1876 static enum_func_status
1877 MYSQLND_METHOD(mysqlnd_conn_data, shutdown)(MYSQLND_CONN_DATA * const conn, uint8_t level)
1878 {
1879 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, shutdown_server);
1880 enum_func_status ret = FAIL;
1881 zend_uchar bits[1];
1882 DBG_ENTER("mysqlnd_conn_data::shutdown");
1883 DBG_INF_FMT("conn=%llu level=%lu", conn->thread_id, level);
1884
1885 if (PASS == conn->m->local_tx_start(conn, this_func)) {
1886 int1store(bits, level);
1887
1888 ret = conn->m->simple_command(conn, COM_SHUTDOWN, bits, 1, PROT_OK_PACKET, FALSE, TRUE);
1889
1890 conn->m->local_tx_end(conn, this_func, ret);
1891 }
1892 DBG_RETURN(ret);
1893 }
1894
1895
1896
1897
1898 static enum_func_status
1899 MYSQLND_METHOD(mysqlnd_conn_data, send_close)(MYSQLND_CONN_DATA * const conn)
1900 {
1901 enum_func_status ret = PASS;
1902 MYSQLND_NET * net = conn->net;
1903 php_stream * net_stream = net->data->m.get_stream(net);
1904 enum mysqlnd_connection_state state;
1905
1906 DBG_ENTER("mysqlnd_send_close");
1907 DBG_INF_FMT("conn=%llu net->data->stream->abstract=%p", conn->thread_id, net_stream? net_stream->abstract:NULL);
1908
1909 if (CONN_GET_STATE(conn) >= CONN_READY) {
1910 MYSQLND_DEC_CONN_STATISTIC(conn->stats, STAT_OPENED_CONNECTIONS);
1911 if (conn->persistent) {
1912 MYSQLND_DEC_CONN_STATISTIC(conn->stats, STAT_OPENED_PERSISTENT_CONNECTIONS);
1913 }
1914 }
1915 state = CONN_GET_STATE(conn);
1916 DBG_INF_FMT("state=%u", state);
1917 switch (state) {
1918 case CONN_READY:
1919 DBG_INF("Connection clean, sending COM_QUIT");
1920 if (net_stream) {
1921 ret = conn->m->simple_command(conn, COM_QUIT, NULL, 0, PROT_LAST, TRUE, TRUE);
1922 net->data->m.close_stream(net, conn->stats, conn->error_info);
1923 }
1924 CONN_SET_STATE(conn, CONN_QUIT_SENT);
1925 break;
1926 case CONN_SENDING_LOAD_DATA:
1927
1928
1929
1930
1931 case CONN_NEXT_RESULT_PENDING:
1932 case CONN_QUERY_SENT:
1933 case CONN_FETCHING_DATA:
1934 MYSQLND_INC_GLOBAL_STATISTIC(STAT_CLOSE_IN_MIDDLE);
1935 DBG_ERR_FMT("Brutally closing connection [%p][%s]", conn, conn->scheme);
1936
1937
1938
1939
1940
1941 case CONN_ALLOCED:
1942
1943
1944
1945
1946
1947
1948 CONN_SET_STATE(conn, CONN_QUIT_SENT);
1949
1950 case CONN_QUIT_SENT:
1951
1952 net->data->m.close_stream(net, conn->stats, conn->error_info);
1953 break;
1954 }
1955
1956 DBG_RETURN(ret);
1957 }
1958
1959
1960
1961
1962 static MYSQLND_CONN_DATA *
1963 MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, get_reference)(MYSQLND_CONN_DATA * const conn)
1964 {
1965 DBG_ENTER("mysqlnd_conn_data::get_reference");
1966 ++conn->refcount;
1967 DBG_INF_FMT("conn=%llu new_refcount=%u", conn->thread_id, conn->refcount);
1968 DBG_RETURN(conn);
1969 }
1970
1971
1972
1973
1974 static enum_func_status
1975 MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, free_reference)(MYSQLND_CONN_DATA * const conn)
1976 {
1977 enum_func_status ret = PASS;
1978 DBG_ENTER("mysqlnd_conn_data::free_reference");
1979 DBG_INF_FMT("conn=%llu old_refcount=%u", conn->thread_id, conn->refcount);
1980 if (!(--conn->refcount)) {
1981
1982
1983
1984
1985
1986 ret = conn->m->send_close(conn);
1987 conn->m->dtor(conn);
1988 }
1989 DBG_RETURN(ret);
1990 }
1991
1992
1993
1994
1995 static enum mysqlnd_connection_state
1996 MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, get_state)(const MYSQLND_CONN_DATA * const conn)
1997 {
1998 DBG_ENTER("mysqlnd_conn_data::get_state");
1999 DBG_RETURN(conn->state);
2000 }
2001
2002
2003
2004
2005 static void
2006 MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, set_state)(MYSQLND_CONN_DATA * const conn, enum mysqlnd_connection_state new_state)
2007 {
2008 DBG_ENTER("mysqlnd_conn_data::set_state");
2009 DBG_INF_FMT("New state=%u", new_state);
2010 conn->state = new_state;
2011 DBG_VOID_RETURN;
2012 }
2013
2014
2015
2016
2017 static unsigned int
2018 MYSQLND_METHOD(mysqlnd_conn_data, field_count)(const MYSQLND_CONN_DATA * const conn)
2019 {
2020 return conn->field_count;
2021 }
2022
2023
2024
2025
2026 static unsigned int
2027 MYSQLND_METHOD(mysqlnd_conn_data, server_status)(const MYSQLND_CONN_DATA * const conn)
2028 {
2029 return conn->upsert_status->server_status;
2030 }
2031
2032
2033
2034
2035 static uint64_t
2036 MYSQLND_METHOD(mysqlnd_conn_data, insert_id)(const MYSQLND_CONN_DATA * const conn)
2037 {
2038 return conn->upsert_status->last_insert_id;
2039 }
2040
2041
2042
2043
2044 static uint64_t
2045 MYSQLND_METHOD(mysqlnd_conn_data, affected_rows)(const MYSQLND_CONN_DATA * const conn)
2046 {
2047 return conn->upsert_status->affected_rows;
2048 }
2049
2050
2051
2052
2053 static unsigned int
2054 MYSQLND_METHOD(mysqlnd_conn_data, warning_count)(const MYSQLND_CONN_DATA * const conn)
2055 {
2056 return conn->upsert_status->warning_count;
2057 }
2058
2059
2060
2061
2062 static const char *
2063 MYSQLND_METHOD(mysqlnd_conn_data, info)(const MYSQLND_CONN_DATA * const conn)
2064 {
2065 return conn->last_message;
2066 }
2067
2068
2069
2070 PHPAPI const char * mysqlnd_get_client_info()
2071 {
2072 return PHP_MYSQLND_VERSION;
2073 }
2074
2075
2076
2077
2078 PHPAPI unsigned int mysqlnd_get_client_version()
2079 {
2080 return MYSQLND_VERSION_ID;
2081 }
2082
2083
2084
2085
2086 static const char *
2087 MYSQLND_METHOD(mysqlnd_conn_data, get_server_info)(const MYSQLND_CONN_DATA * const conn)
2088 {
2089 return conn->server_version;
2090 }
2091
2092
2093
2094
2095 static const char *
2096 MYSQLND_METHOD(mysqlnd_conn_data, get_host_info)(const MYSQLND_CONN_DATA * const conn)
2097 {
2098 return conn->host_info;
2099 }
2100
2101
2102
2103
2104 static unsigned int
2105 MYSQLND_METHOD(mysqlnd_conn_data, get_proto_info)(const MYSQLND_CONN_DATA * const conn)
2106 {
2107 return conn->protocol_version;
2108 }
2109
2110
2111
2112
2113 static const char *
2114 MYSQLND_METHOD(mysqlnd_conn_data, charset_name)(const MYSQLND_CONN_DATA * const conn)
2115 {
2116 return conn->charset->name;
2117 }
2118
2119
2120
2121
2122 static uint64_t
2123 MYSQLND_METHOD(mysqlnd_conn_data, thread_id)(const MYSQLND_CONN_DATA * const conn)
2124 {
2125 return conn->thread_id;
2126 }
2127
2128
2129
2130
2131 static zend_ulong
2132 MYSQLND_METHOD(mysqlnd_conn_data, get_server_version)(const MYSQLND_CONN_DATA * const conn)
2133 {
2134 zend_long major, minor, patch;
2135 char *p;
2136
2137 if (!(p = conn->server_version)) {
2138 return 0;
2139 }
2140
2141 major = ZEND_STRTOL(p, &p, 10);
2142 p += 1;
2143 minor = ZEND_STRTOL(p, &p, 10);
2144 p += 1;
2145 patch = ZEND_STRTOL(p, &p, 10);
2146
2147 return (zend_ulong)(major * Z_L(10000) + (zend_ulong)(minor * Z_L(100) + patch));
2148 }
2149
2150
2151
2152
2153 static zend_bool
2154 MYSQLND_METHOD(mysqlnd_conn_data, more_results)(const MYSQLND_CONN_DATA * const conn)
2155 {
2156 DBG_ENTER("mysqlnd_conn_data::more_results");
2157
2158 DBG_RETURN(conn->upsert_status->server_status & SERVER_MORE_RESULTS_EXISTS? TRUE:FALSE);
2159 }
2160
2161
2162
2163
2164 static enum_func_status
2165 MYSQLND_METHOD(mysqlnd_conn_data, next_result)(MYSQLND_CONN_DATA * const conn)
2166 {
2167 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, next_result);
2168 enum_func_status ret = FAIL;
2169
2170 DBG_ENTER("mysqlnd_conn_data::next_result");
2171 DBG_INF_FMT("conn=%llu", conn->thread_id);
2172
2173 if (PASS == conn->m->local_tx_start(conn, this_func)) {
2174 do {
2175 if (CONN_GET_STATE(conn) != CONN_NEXT_RESULT_PENDING) {
2176 break;
2177 }
2178
2179 SET_EMPTY_ERROR(*conn->error_info);
2180 SET_ERROR_AFF_ROWS(conn);
2181
2182
2183
2184
2185 if (FAIL == (ret = conn->m->query_read_result_set_header(conn, NULL))) {
2186
2187
2188
2189
2190 if (!conn->error_info->error_no) {
2191 DBG_ERR_FMT("Serious error. %s::%u", __FILE__, __LINE__);
2192 php_error_docref(NULL, E_WARNING, "Serious error. PID=%d", getpid());
2193 CONN_SET_STATE(conn, CONN_QUIT_SENT);
2194 conn->m->send_close(conn);
2195 } else {
2196 DBG_INF_FMT("Error from the server : (%u) %s", conn->error_info->error_no, conn->error_info->error);
2197 }
2198 break;
2199 }
2200 if (conn->last_query_type == QUERY_UPSERT && conn->upsert_status->affected_rows) {
2201 MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn->stats, STAT_ROWS_AFFECTED_NORMAL, conn->upsert_status->affected_rows);
2202 }
2203 } while (0);
2204 conn->m->local_tx_end(conn, this_func, ret);
2205 }
2206
2207 DBG_RETURN(ret);
2208 }
2209
2210
2211
2212
2213 PHPAPI const char *mysqlnd_field_type_name(enum mysqlnd_field_types field_type)
2214 {
2215 switch(field_type) {
2216 case FIELD_TYPE_JSON:
2217 return "json";
2218 case FIELD_TYPE_STRING:
2219 case FIELD_TYPE_VAR_STRING:
2220 return "string";
2221 case FIELD_TYPE_TINY:
2222 case FIELD_TYPE_SHORT:
2223 case FIELD_TYPE_LONG:
2224 case FIELD_TYPE_LONGLONG:
2225 case FIELD_TYPE_INT24:
2226 return "int";
2227 case FIELD_TYPE_FLOAT:
2228 case FIELD_TYPE_DOUBLE:
2229 case FIELD_TYPE_DECIMAL:
2230 case FIELD_TYPE_NEWDECIMAL:
2231 return "real";
2232 case FIELD_TYPE_TIMESTAMP:
2233 return "timestamp";
2234 case FIELD_TYPE_YEAR:
2235 return "year";
2236 case FIELD_TYPE_DATE:
2237 case FIELD_TYPE_NEWDATE:
2238 return "date";
2239 case FIELD_TYPE_TIME:
2240 return "time";
2241 case FIELD_TYPE_SET:
2242 return "set";
2243 case FIELD_TYPE_ENUM:
2244 return "enum";
2245 case FIELD_TYPE_GEOMETRY:
2246 return "geometry";
2247 case FIELD_TYPE_DATETIME:
2248 return "datetime";
2249 case FIELD_TYPE_TINY_BLOB:
2250 case FIELD_TYPE_MEDIUM_BLOB:
2251 case FIELD_TYPE_LONG_BLOB:
2252 case FIELD_TYPE_BLOB:
2253 return "blob";
2254 case FIELD_TYPE_NULL:
2255 return "null";
2256 case FIELD_TYPE_BIT:
2257 return "bit";
2258 default:
2259 return "unknown";
2260 }
2261 }
2262
2263
2264
2265
2266 static enum_func_status
2267 MYSQLND_METHOD(mysqlnd_conn_data, change_user)(MYSQLND_CONN_DATA * const conn,
2268 const char * user,
2269 const char * passwd,
2270 const char * db,
2271 zend_bool silent,
2272 size_t passwd_len
2273 )
2274 {
2275 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, change_user);
2276 enum_func_status ret = FAIL;
2277
2278 DBG_ENTER("mysqlnd_conn_data::change_user");
2279 DBG_INF_FMT("conn=%llu user=%s passwd=%s db=%s silent=%u",
2280 conn->thread_id, user?user:"", passwd?"***":"null", db?db:"", (silent == TRUE)?1:0 );
2281
2282 if (PASS != conn->m->local_tx_start(conn, this_func)) {
2283 goto end;
2284 }
2285
2286 SET_EMPTY_ERROR(*conn->error_info);
2287 SET_ERROR_AFF_ROWS(conn);
2288
2289 if (!user) {
2290 user = "";
2291 }
2292 if (!passwd) {
2293 passwd = "";
2294 }
2295 if (!db) {
2296 db = "";
2297 }
2298
2299
2300 ret = mysqlnd_run_authentication(conn, user, passwd, passwd_len, db, strlen(db),
2301 conn->auth_plugin_data, conn->auth_plugin_data_len, conn->options->auth_protocol,
2302 0 , conn->options, conn->server_capabilities, silent, TRUE);
2303
2304
2305
2306
2307
2308 conn->m->local_tx_end(conn, this_func, ret);
2309 end:
2310 DBG_INF(ret == PASS? "PASS":"FAIL");
2311 DBG_RETURN(ret);
2312 }
2313
2314
2315
2316
2317 static enum_func_status
2318 MYSQLND_METHOD(mysqlnd_conn_data, set_client_option)(MYSQLND_CONN_DATA * const conn,
2319 enum mysqlnd_option option,
2320 const char * const value
2321 )
2322 {
2323 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, set_client_option);
2324 enum_func_status ret = PASS;
2325 DBG_ENTER("mysqlnd_conn_data::set_client_option");
2326 DBG_INF_FMT("conn=%llu option=%u", conn->thread_id, option);
2327
2328 if (PASS != conn->m->local_tx_start(conn, this_func)) {
2329 goto end;
2330 }
2331 switch (option) {
2332 case MYSQL_OPT_COMPRESS:
2333 #ifdef WHEN_SUPPORTED_BY_MYSQLI
2334 case MYSQL_OPT_READ_TIMEOUT:
2335 case MYSQL_OPT_WRITE_TIMEOUT:
2336 #endif
2337 case MYSQLND_OPT_SSL_KEY:
2338 case MYSQLND_OPT_SSL_CERT:
2339 case MYSQLND_OPT_SSL_CA:
2340 case MYSQLND_OPT_SSL_CAPATH:
2341 case MYSQLND_OPT_SSL_CIPHER:
2342 case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
2343 case MYSQL_OPT_CONNECT_TIMEOUT:
2344 case MYSQLND_OPT_NET_CMD_BUFFER_SIZE:
2345 case MYSQLND_OPT_NET_READ_BUFFER_SIZE:
2346 case MYSQL_SERVER_PUBLIC_KEY:
2347 ret = conn->net->data->m.set_client_option(conn->net, option, value);
2348 break;
2349 #ifdef MYSQLND_STRING_TO_INT_CONVERSION
2350 case MYSQLND_OPT_INT_AND_FLOAT_NATIVE:
2351 conn->options->int_and_float_native = *(unsigned int*) value;
2352 break;
2353 #endif
2354 case MYSQL_OPT_LOCAL_INFILE:
2355 if (value && (*(unsigned int*) value) ? 1 : 0) {
2356 conn->options->flags |= CLIENT_LOCAL_FILES;
2357 } else {
2358 conn->options->flags &= ~CLIENT_LOCAL_FILES;
2359 }
2360 break;
2361 case MYSQL_INIT_COMMAND:
2362 {
2363 char ** new_init_commands;
2364 char * new_command;
2365
2366
2367 new_init_commands = mnd_perealloc(conn->options->init_commands, sizeof(char *) * (conn->options->num_commands + 1), conn->persistent);
2368 if (!new_init_commands) {
2369 goto oom;
2370 }
2371 conn->options->init_commands = new_init_commands;
2372 new_command = mnd_pestrdup(value, conn->persistent);
2373 if (!new_command) {
2374 goto oom;
2375 }
2376 conn->options->init_commands[conn->options->num_commands] = new_command;
2377 ++conn->options->num_commands;
2378 break;
2379 }
2380 case MYSQL_READ_DEFAULT_FILE:
2381 case MYSQL_READ_DEFAULT_GROUP:
2382 #ifdef WHEN_SUPPORTED_BY_MYSQLI
2383 case MYSQL_SET_CLIENT_IP:
2384 case MYSQL_REPORT_DATA_TRUNCATION:
2385 #endif
2386
2387 break;
2388 case MYSQL_SET_CHARSET_NAME:
2389 {
2390 char * new_charset_name;
2391 if (!mysqlnd_find_charset_name(value)) {
2392 SET_CLIENT_ERROR(*conn->error_info, CR_CANT_FIND_CHARSET, UNKNOWN_SQLSTATE, "Unknown character set");
2393 ret = FAIL;
2394 break;
2395 }
2396
2397 new_charset_name = mnd_pestrdup(value, conn->persistent);
2398 if (!new_charset_name) {
2399 goto oom;
2400 }
2401 if (conn->options->charset_name) {
2402 mnd_pefree(conn->options->charset_name, conn->persistent);
2403 }
2404 conn->options->charset_name = new_charset_name;
2405 DBG_INF_FMT("charset=%s", conn->options->charset_name);
2406 break;
2407 }
2408 case MYSQL_OPT_NAMED_PIPE:
2409 conn->options->protocol = MYSQL_PROTOCOL_PIPE;
2410 break;
2411 case MYSQL_OPT_PROTOCOL:
2412 if (*(unsigned int*) value < MYSQL_PROTOCOL_LAST) {
2413 conn->options->protocol = *(unsigned int*) value;
2414 }
2415 break;
2416 #ifdef WHEN_SUPPORTED_BY_MYSQLI
2417 case MYSQL_SET_CHARSET_DIR:
2418 case MYSQL_OPT_RECONNECT:
2419
2420
2421
2422 case MYSQL_OPT_USE_REMOTE_CONNECTION:
2423 case MYSQL_OPT_USE_EMBEDDED_CONNECTION:
2424 case MYSQL_OPT_GUESS_CONNECTION:
2425
2426 break;
2427 #endif
2428 case MYSQLND_OPT_MAX_ALLOWED_PACKET:
2429 if (*(unsigned int*) value > (1<<16)) {
2430 conn->options->max_allowed_packet = *(unsigned int*) value;
2431 }
2432 break;
2433 case MYSQLND_OPT_AUTH_PROTOCOL:
2434 {
2435 char * new_auth_protocol = value? mnd_pestrdup(value, conn->persistent) : NULL;
2436 if (value && !new_auth_protocol) {
2437 goto oom;
2438 }
2439 if (conn->options->auth_protocol) {
2440 mnd_pefree(conn->options->auth_protocol, conn->persistent);
2441 }
2442 conn->options->auth_protocol = new_auth_protocol;
2443 DBG_INF_FMT("auth_protocol=%s", conn->options->auth_protocol);
2444 break;
2445 }
2446 case MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS:
2447 if (value && (*(unsigned int*) value) ? 1 : 0) {
2448 conn->options->flags |= CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS;
2449 } else {
2450 conn->options->flags &= ~CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS;
2451 }
2452 break;
2453 case MYSQL_OPT_CONNECT_ATTR_RESET:
2454 if (conn->options->connect_attr) {
2455 DBG_INF_FMT("Before reset %d attribute(s)", zend_hash_num_elements(conn->options->connect_attr));
2456 zend_hash_clean(conn->options->connect_attr);
2457 }
2458 break;
2459 case MYSQL_OPT_CONNECT_ATTR_DELETE:
2460 if (conn->options->connect_attr && value) {
2461 DBG_INF_FMT("Before delete %d attribute(s)", zend_hash_num_elements(conn->options->connect_attr));
2462 zend_hash_str_del(conn->options->connect_attr, value, strlen(value));
2463 DBG_INF_FMT("%d left", zend_hash_num_elements(conn->options->connect_attr));
2464 }
2465 break;
2466 #ifdef WHEN_SUPPORTED_BY_MYSQLI
2467 case MYSQL_SHARED_MEMORY_BASE_NAME:
2468 case MYSQL_OPT_USE_RESULT:
2469 case MYSQL_SECURE_AUTH:
2470
2471 #endif
2472 default:
2473 ret = FAIL;
2474 }
2475 conn->m->local_tx_end(conn, this_func, ret);
2476 DBG_RETURN(ret);
2477 oom:
2478 SET_OOM_ERROR(*conn->error_info);
2479 conn->m->local_tx_end(conn, this_func, FAIL);
2480 end:
2481 DBG_RETURN(FAIL);
2482 }
2483
2484
2485
2486
2487 static enum_func_status
2488 MYSQLND_METHOD(mysqlnd_conn_data, set_client_option_2d)(MYSQLND_CONN_DATA * const conn,
2489 enum mysqlnd_option option,
2490 const char * const key,
2491 const char * const value
2492 )
2493 {
2494 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, set_client_option_2d);
2495 enum_func_status ret = PASS;
2496 DBG_ENTER("mysqlnd_conn_data::set_client_option_2d");
2497 DBG_INF_FMT("conn=%llu option=%u", conn->thread_id, option);
2498
2499 if (PASS != conn->m->local_tx_start(conn, this_func)) {
2500 goto end;
2501 }
2502 switch (option) {
2503 case MYSQL_OPT_CONNECT_ATTR_ADD:
2504 if (!conn->options->connect_attr) {
2505 DBG_INF("Initializing connect_attr hash");
2506 conn->options->connect_attr = mnd_pemalloc(sizeof(HashTable), conn->persistent);
2507 if (!conn->options->connect_attr) {
2508 goto oom;
2509 }
2510 zend_hash_init(conn->options->connect_attr, 0, NULL, ZVAL_PTR_DTOR, conn->persistent);
2511 }
2512 DBG_INF_FMT("Adding [%s][%s]", key, value);
2513 {
2514 zval attrz;
2515 ZVAL_NEW_STR(&attrz, zend_string_init(value, strlen(value), 1));
2516 zend_hash_str_update(conn->options->connect_attr, key, strlen(key), &attrz);
2517 }
2518 break;
2519 default:
2520 ret = FAIL;
2521 }
2522 conn->m->local_tx_end(conn, this_func, ret);
2523 DBG_RETURN(ret);
2524 oom:
2525 SET_OOM_ERROR(*conn->error_info);
2526 conn->m->local_tx_end(conn, this_func, FAIL);
2527 end:
2528 DBG_RETURN(FAIL);
2529 }
2530
2531
2532
2533
2534 static MYSQLND_RES *
2535 MYSQLND_METHOD(mysqlnd_conn_data, use_result)(MYSQLND_CONN_DATA * const conn, const unsigned int flags)
2536 {
2537 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, use_result);
2538 MYSQLND_RES * result = NULL;
2539
2540 DBG_ENTER("mysqlnd_conn_data::use_result");
2541 DBG_INF_FMT("conn=%llu", conn->thread_id);
2542
2543 if (PASS == conn->m->local_tx_start(conn, this_func)) {
2544 do {
2545 if (!conn->current_result) {
2546 break;
2547 }
2548
2549
2550 if (conn->last_query_type != QUERY_SELECT || CONN_GET_STATE(conn) != CONN_FETCHING_DATA) {
2551 SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
2552 DBG_ERR("Command out of sync");
2553 break;
2554 }
2555
2556 MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_UNBUFFERED_SETS);
2557
2558 conn->current_result->conn = conn->m->get_reference(conn);
2559 result = conn->current_result->m.use_result(conn->current_result, FALSE);
2560
2561 if (!result) {
2562 conn->current_result->m.free_result(conn->current_result, TRUE);
2563 }
2564 conn->current_result = NULL;
2565 } while (0);
2566
2567 conn->m->local_tx_end(conn, this_func, result == NULL? FAIL:PASS);
2568 }
2569
2570 DBG_RETURN(result);
2571 }
2572
2573
2574
2575
2576 static MYSQLND_RES *
2577 MYSQLND_METHOD(mysqlnd_conn_data, store_result)(MYSQLND_CONN_DATA * const conn, const unsigned int flags)
2578 {
2579 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, store_result);
2580 MYSQLND_RES * result = NULL;
2581
2582 DBG_ENTER("mysqlnd_conn_data::store_result");
2583 DBG_INF_FMT("conn=%llu conn=%p", conn->thread_id, conn);
2584
2585 if (PASS == conn->m->local_tx_start(conn, this_func)) {
2586 do {
2587 unsigned int f = flags;
2588 if (!conn->current_result) {
2589 break;
2590 }
2591
2592
2593 if (conn->last_query_type != QUERY_SELECT || CONN_GET_STATE(conn) != CONN_FETCHING_DATA) {
2594 SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
2595 DBG_ERR("Command out of sync");
2596 break;
2597 }
2598
2599 MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_BUFFERED_SETS);
2600
2601
2602 if ((conn->m->get_client_api_capabilities(conn) & MYSQLND_CLIENT_KNOWS_RSET_COPY_DATA)) {
2603 if (MYSQLND_G(fetch_data_copy)) {
2604 f &= ~MYSQLND_STORE_NO_COPY;
2605 f |= MYSQLND_STORE_COPY;
2606 }
2607 } else {
2608
2609 if (!(f & (MYSQLND_STORE_NO_COPY | MYSQLND_STORE_COPY))) {
2610 f |= MYSQLND_STORE_COPY;
2611 }
2612 }
2613 if (!(f & (MYSQLND_STORE_NO_COPY | MYSQLND_STORE_COPY))) {
2614 SET_CLIENT_ERROR(*conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "Unknown fetch mode");
2615 DBG_ERR("Unknown fetch mode");
2616 break;
2617 }
2618 result = conn->current_result->m.store_result(conn->current_result, conn, f);
2619 if (!result) {
2620 conn->current_result->m.free_result(conn->current_result, TRUE);
2621 }
2622 conn->current_result = NULL;
2623 } while (0);
2624
2625 conn->m->local_tx_end(conn, this_func, result == NULL? FAIL:PASS);
2626 }
2627 DBG_RETURN(result);
2628 }
2629
2630
2631
2632
2633 static void
2634 MYSQLND_METHOD(mysqlnd_conn_data, get_connection_stats)(const MYSQLND_CONN_DATA * const conn,
2635 zval * return_value ZEND_FILE_LINE_DC)
2636 {
2637 DBG_ENTER("mysqlnd_conn_data::get_connection_stats");
2638 mysqlnd_fill_stats_hash(conn->stats, mysqlnd_stats_values_names, return_value ZEND_FILE_LINE_CC);
2639 DBG_VOID_RETURN;
2640 }
2641
2642
2643
2644
2645 static enum_func_status
2646 MYSQLND_METHOD(mysqlnd_conn_data, set_autocommit)(MYSQLND_CONN_DATA * conn, unsigned int mode)
2647 {
2648 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, set_autocommit);
2649 enum_func_status ret = FAIL;
2650 DBG_ENTER("mysqlnd_conn_data::set_autocommit");
2651
2652 if (PASS == conn->m->local_tx_start(conn, this_func)) {
2653 ret = conn->m->query(conn, (mode) ? "SET AUTOCOMMIT=1":"SET AUTOCOMMIT=0", sizeof("SET AUTOCOMMIT=1") - 1);
2654 conn->m->local_tx_end(conn, this_func, ret);
2655 }
2656
2657 DBG_RETURN(ret);
2658 }
2659
2660
2661
2662
2663 static enum_func_status
2664 MYSQLND_METHOD(mysqlnd_conn_data, tx_commit)(MYSQLND_CONN_DATA * conn)
2665 {
2666 return conn->m->tx_commit_or_rollback(conn, TRUE, TRANS_COR_NO_OPT, NULL);
2667 }
2668
2669
2670
2671
2672 static enum_func_status
2673 MYSQLND_METHOD(mysqlnd_conn_data, tx_rollback)(MYSQLND_CONN_DATA * conn)
2674 {
2675 return conn->m->tx_commit_or_rollback(conn, FALSE, TRANS_COR_NO_OPT, NULL);
2676 }
2677
2678
2679
2680
2681 static void
2682 MYSQLND_METHOD(mysqlnd_conn_data, tx_cor_options_to_string)(const MYSQLND_CONN_DATA * const conn, smart_str * str, const unsigned int mode)
2683 {
2684 if (mode & TRANS_COR_AND_CHAIN && !(mode & TRANS_COR_AND_NO_CHAIN)) {
2685 if (str->s && ZSTR_LEN(str->s)) {
2686 smart_str_appendl(str, " ", sizeof(" ") - 1);
2687 }
2688 smart_str_appendl(str, "AND CHAIN", sizeof("AND CHAIN") - 1);
2689 } else if (mode & TRANS_COR_AND_NO_CHAIN && !(mode & TRANS_COR_AND_CHAIN)) {
2690 if (str->s && ZSTR_LEN(str->s)) {
2691 smart_str_appendl(str, " ", sizeof(" ") - 1);
2692 }
2693 smart_str_appendl(str, "AND NO CHAIN", sizeof("AND NO CHAIN") - 1);
2694 }
2695
2696 if (mode & TRANS_COR_RELEASE && !(mode & TRANS_COR_NO_RELEASE)) {
2697 if (str->s && ZSTR_LEN(str->s)) {
2698 smart_str_appendl(str, " ", sizeof(" ") - 1);
2699 }
2700 smart_str_appendl(str, "RELEASE", sizeof("RELEASE") - 1);
2701 } else if (mode & TRANS_COR_NO_RELEASE && !(mode & TRANS_COR_RELEASE)) {
2702 if (str->s && ZSTR_LEN(str->s)) {
2703 smart_str_appendl(str, " ", sizeof(" ") - 1);
2704 }
2705 smart_str_appendl(str, "NO RELEASE", sizeof("NO RELEASE") - 1);
2706 }
2707 smart_str_0(str);
2708 }
2709
2710
2711
2712
2713 static char *
2714 mysqlnd_escape_string_for_tx_name_in_comment(const char * const name)
2715 {
2716 char * ret = NULL;
2717 DBG_ENTER("mysqlnd_escape_string_for_tx_name_in_comment");
2718 if (name) {
2719 zend_bool warned = FALSE;
2720 const char * p_orig = name;
2721 char * p_copy;
2722 p_copy = ret = mnd_emalloc(strlen(name) + 1 + 2 + 2 + 1);
2723 *p_copy++ = ' ';
2724 *p_copy++ = '/';
2725 *p_copy++ = '*';
2726 while (1) {
2727 register char v = *p_orig;
2728 if (v == 0) {
2729 break;
2730 }
2731 if ((v >= '0' && v <= '9') ||
2732 (v >= 'a' && v <= 'z') ||
2733 (v >= 'A' && v <= 'Z') ||
2734 v == '-' ||
2735 v == '_' ||
2736 v == ' ' ||
2737 v == '=')
2738 {
2739 *p_copy++ = v;
2740 } else if (warned == FALSE) {
2741 php_error_docref(NULL, E_WARNING, "Transaction name truncated. Must be only [0-9A-Za-z\\-_=]+");
2742 warned = TRUE;
2743 }
2744 ++p_orig;
2745 }
2746 *p_copy++ = '*';
2747 *p_copy++ = '/';
2748 *p_copy++ = 0;
2749 }
2750 DBG_RETURN(ret);
2751 }
2752
2753
2754
2755
2756 static enum_func_status
2757 MYSQLND_METHOD(mysqlnd_conn_data, tx_commit_or_rollback)(MYSQLND_CONN_DATA * conn, const zend_bool commit, const unsigned int flags, const char * const name)
2758 {
2759 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, tx_commit_or_rollback);
2760 enum_func_status ret = FAIL;
2761 DBG_ENTER("mysqlnd_conn_data::tx_commit_or_rollback");
2762
2763 if (PASS == conn->m->local_tx_start(conn, this_func)) {
2764 do {
2765 smart_str tmp_str = {0, 0};
2766 conn->m->tx_cor_options_to_string(conn, &tmp_str, flags);
2767 smart_str_0(&tmp_str);
2768
2769
2770 {
2771 char * query;
2772 size_t query_len;
2773 char * name_esc = mysqlnd_escape_string_for_tx_name_in_comment(name);
2774
2775 query_len = mnd_sprintf(&query, 0, (commit? "COMMIT%s %s":"ROLLBACK%s %s"),
2776 name_esc? name_esc:"", tmp_str.s? ZSTR_VAL(tmp_str.s):"");
2777 smart_str_free(&tmp_str);
2778 if (name_esc) {
2779 mnd_efree(name_esc);
2780 name_esc = NULL;
2781 }
2782 if (!query) {
2783 SET_OOM_ERROR(*conn->error_info);
2784 break;
2785 }
2786
2787 ret = conn->m->query(conn, query, query_len);
2788 mnd_sprintf_free(query);
2789 }
2790 } while (0);
2791 conn->m->local_tx_end(conn, this_func, ret);
2792 }
2793
2794 DBG_RETURN(ret);
2795 }
2796
2797
2798
2799
2800 static enum_func_status
2801 MYSQLND_METHOD(mysqlnd_conn_data, tx_begin)(MYSQLND_CONN_DATA * conn, const unsigned int mode, const char * const name)
2802 {
2803 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, tx_begin);
2804 enum_func_status ret = FAIL;
2805 DBG_ENTER("mysqlnd_conn_data::tx_begin");
2806
2807 if (PASS == conn->m->local_tx_start(conn, this_func)) {
2808 do {
2809 smart_str tmp_str = {0, 0};
2810 if (mode & TRANS_START_WITH_CONSISTENT_SNAPSHOT) {
2811 if (tmp_str.s) {
2812 smart_str_appendl(&tmp_str, ", ", sizeof(", ") - 1);
2813 }
2814 smart_str_appendl(&tmp_str, "WITH CONSISTENT SNAPSHOT", sizeof("WITH CONSISTENT SNAPSHOT") - 1);
2815 }
2816 if (mode & (TRANS_START_READ_WRITE | TRANS_START_READ_ONLY)) {
2817 zend_ulong server_version = conn->m->get_server_version(conn);
2818 if (server_version < 50605L) {
2819 php_error_docref(NULL, E_WARNING, "This server version doesn't support 'READ WRITE' and 'READ ONLY'. Minimum 5.6.5 is required");
2820 smart_str_free(&tmp_str);
2821 break;
2822 } else if (mode & TRANS_START_READ_WRITE) {
2823 if (tmp_str.s && ZSTR_LEN(tmp_str.s)) {
2824 smart_str_appendl(&tmp_str, ", ", sizeof(", ") - 1);
2825 }
2826 smart_str_appendl(&tmp_str, "READ WRITE", sizeof("READ WRITE") - 1);
2827 } else if (mode & TRANS_START_READ_ONLY) {
2828 if (tmp_str.s && ZSTR_LEN(tmp_str.s)) {
2829 smart_str_appendl(&tmp_str, ", ", sizeof(", ") - 1);
2830 }
2831 smart_str_appendl(&tmp_str, "READ ONLY", sizeof("READ ONLY") - 1);
2832 }
2833 }
2834 smart_str_0(&tmp_str);
2835
2836 {
2837 char * name_esc = mysqlnd_escape_string_for_tx_name_in_comment(name);
2838 char * query;
2839 unsigned int query_len = mnd_sprintf(&query, 0, "START TRANSACTION%s %s", name_esc? name_esc:"", tmp_str.s? ZSTR_VAL(tmp_str.s):"");
2840 smart_str_free(&tmp_str);
2841 if (name_esc) {
2842 mnd_efree(name_esc);
2843 name_esc = NULL;
2844 }
2845 if (!query) {
2846 SET_OOM_ERROR(*conn->error_info);
2847 break;
2848 }
2849 ret = conn->m->query(conn, query, query_len);
2850 mnd_sprintf_free(query);
2851 }
2852 } while (0);
2853 conn->m->local_tx_end(conn, this_func, ret);
2854 }
2855
2856 DBG_RETURN(ret);
2857 }
2858
2859
2860
2861
2862 static enum_func_status
2863 MYSQLND_METHOD(mysqlnd_conn_data, tx_savepoint)(MYSQLND_CONN_DATA * conn, const char * const name)
2864 {
2865 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, tx_savepoint);
2866 enum_func_status ret = FAIL;
2867 DBG_ENTER("mysqlnd_conn_data::tx_savepoint");
2868
2869 if (PASS == conn->m->local_tx_start(conn, this_func)) {
2870 do {
2871 char * query;
2872 unsigned int query_len;
2873 if (!name) {
2874 SET_CLIENT_ERROR(*conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "Savepoint name not provided");
2875 break;
2876 }
2877 query_len = mnd_sprintf(&query, 0, "SAVEPOINT `%s`", name);
2878 if (!query) {
2879 SET_OOM_ERROR(*conn->error_info);
2880 break;
2881 }
2882 ret = conn->m->query(conn, query, query_len);
2883 mnd_sprintf_free(query);
2884 } while (0);
2885 conn->m->local_tx_end(conn, this_func, ret);
2886 }
2887
2888 DBG_RETURN(ret);
2889 }
2890
2891
2892
2893
2894 static enum_func_status
2895 MYSQLND_METHOD(mysqlnd_conn_data, tx_savepoint_release)(MYSQLND_CONN_DATA * conn, const char * const name)
2896 {
2897 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, tx_savepoint_release);
2898 enum_func_status ret = FAIL;
2899 DBG_ENTER("mysqlnd_conn_data::tx_savepoint_release");
2900
2901 if (PASS == conn->m->local_tx_start(conn, this_func)) {
2902 do {
2903 char * query;
2904 unsigned int query_len;
2905 if (!name) {
2906 SET_CLIENT_ERROR(*conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "Savepoint name not provided");
2907 break;
2908 }
2909 query_len = mnd_sprintf(&query, 0, "RELEASE SAVEPOINT `%s`", name);
2910 if (!query) {
2911 SET_OOM_ERROR(*conn->error_info);
2912 break;
2913 }
2914 ret = conn->m->query(conn, query, query_len);
2915 mnd_sprintf_free(query);
2916 } while (0);
2917 conn->m->local_tx_end(conn, this_func, ret);
2918 }
2919
2920 DBG_RETURN(ret);
2921 }
2922
2923
2924
2925
2926 static unsigned int
2927 MYSQLND_METHOD(mysqlnd_conn_data, negotiate_client_api_capabilities)(MYSQLND_CONN_DATA * const conn, const unsigned int flags)
2928 {
2929 unsigned int ret = 0;
2930 DBG_ENTER("mysqlnd_conn_data::negotiate_client_api_capabilities");
2931 if (conn) {
2932 ret = conn->client_api_capabilities;
2933 conn->client_api_capabilities = flags;
2934 }
2935
2936 DBG_RETURN(ret);
2937 }
2938
2939
2940
2941
2942 static unsigned int
2943 MYSQLND_METHOD(mysqlnd_conn_data, get_client_api_capabilities)(const MYSQLND_CONN_DATA * const conn)
2944 {
2945 DBG_ENTER("mysqlnd_conn_data::get_client_api_capabilities");
2946 DBG_RETURN(conn? conn->client_api_capabilities : 0);
2947 }
2948
2949
2950
2951
2952 static enum_func_status
2953 MYSQLND_METHOD(mysqlnd_conn_data, local_tx_start)(MYSQLND_CONN_DATA * conn, size_t this_func)
2954 {
2955 enum_func_status ret = PASS;
2956 DBG_ENTER("mysqlnd_conn_data::local_tx_start");
2957 DBG_RETURN(ret);
2958 }
2959
2960
2961
2962
2963 static enum_func_status
2964 MYSQLND_METHOD(mysqlnd_conn_data, local_tx_end)(MYSQLND_CONN_DATA * conn, size_t this_func, enum_func_status status)
2965 {
2966 DBG_ENTER("mysqlnd_conn_data::local_tx_end");
2967 DBG_RETURN(status);
2968 }
2969
2970
2971
2972
2973 static enum_func_status
2974 MYSQLND_METHOD(mysqlnd_conn_data, init)(MYSQLND_CONN_DATA * conn)
2975 {
2976 DBG_ENTER("mysqlnd_conn_data::init");
2977 mysqlnd_stats_init(&conn->stats, STAT_LAST, conn->persistent);
2978 SET_ERROR_AFF_ROWS(conn);
2979
2980 conn->net = mysqlnd_net_init(conn->persistent, conn->stats, conn->error_info);
2981 conn->protocol = mysqlnd_protocol_init(conn->persistent);
2982
2983 DBG_RETURN(conn->stats && conn->net && conn->protocol? PASS:FAIL);
2984 }
2985
2986
2987
2988 MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND_CONN_DATA * const conn);
2989
2990
2991 MYSQLND_CLASS_METHODS_START(mysqlnd_conn_data)
2992 MYSQLND_METHOD(mysqlnd_conn_data, init),
2993 MYSQLND_METHOD(mysqlnd_conn_data, connect),
2994
2995 MYSQLND_METHOD(mysqlnd_conn_data, escape_string),
2996 MYSQLND_METHOD(mysqlnd_conn_data, set_charset),
2997 MYSQLND_METHOD(mysqlnd_conn_data, query),
2998 MYSQLND_METHOD(mysqlnd_conn_data, send_query),
2999 MYSQLND_METHOD(mysqlnd_conn_data, reap_query),
3000 MYSQLND_METHOD(mysqlnd_conn_data, use_result),
3001 MYSQLND_METHOD(mysqlnd_conn_data, store_result),
3002 MYSQLND_METHOD(mysqlnd_conn_data, next_result),
3003 MYSQLND_METHOD(mysqlnd_conn_data, more_results),
3004
3005 _mysqlnd_stmt_init,
3006
3007 MYSQLND_METHOD(mysqlnd_conn_data, shutdown),
3008 MYSQLND_METHOD(mysqlnd_conn_data, refresh),
3009
3010 MYSQLND_METHOD(mysqlnd_conn_data, ping),
3011 MYSQLND_METHOD(mysqlnd_conn_data, kill),
3012 MYSQLND_METHOD(mysqlnd_conn_data, select_db),
3013 MYSQLND_METHOD(mysqlnd_conn_data, dump_debug_info),
3014 MYSQLND_METHOD(mysqlnd_conn_data, change_user),
3015
3016 MYSQLND_METHOD(mysqlnd_conn_data, errno),
3017 MYSQLND_METHOD(mysqlnd_conn_data, error),
3018 MYSQLND_METHOD(mysqlnd_conn_data, sqlstate),
3019 MYSQLND_METHOD(mysqlnd_conn_data, thread_id),
3020
3021 MYSQLND_METHOD(mysqlnd_conn_data, get_connection_stats),
3022
3023 MYSQLND_METHOD(mysqlnd_conn_data, get_server_version),
3024 MYSQLND_METHOD(mysqlnd_conn_data, get_server_info),
3025 MYSQLND_METHOD(mysqlnd_conn_data, statistic),
3026 MYSQLND_METHOD(mysqlnd_conn_data, get_host_info),
3027 MYSQLND_METHOD(mysqlnd_conn_data, get_proto_info),
3028 MYSQLND_METHOD(mysqlnd_conn_data, info),
3029 MYSQLND_METHOD(mysqlnd_conn_data, charset_name),
3030 MYSQLND_METHOD(mysqlnd_conn_data, list_fields),
3031 MYSQLND_METHOD(mysqlnd_conn_data, list_method),
3032
3033 MYSQLND_METHOD(mysqlnd_conn_data, insert_id),
3034 MYSQLND_METHOD(mysqlnd_conn_data, affected_rows),
3035 MYSQLND_METHOD(mysqlnd_conn_data, warning_count),
3036 MYSQLND_METHOD(mysqlnd_conn_data, field_count),
3037
3038 MYSQLND_METHOD(mysqlnd_conn_data, server_status),
3039
3040 MYSQLND_METHOD(mysqlnd_conn_data, set_server_option),
3041 MYSQLND_METHOD(mysqlnd_conn_data, set_client_option),
3042 MYSQLND_METHOD(mysqlnd_conn_data, free_contents),
3043 MYSQLND_METHOD(mysqlnd_conn_data, free_options),
3044
3045 MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, dtor),
3046
3047 mysqlnd_query_read_result_set_header,
3048
3049 MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, get_reference),
3050 MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, free_reference),
3051 MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, get_state),
3052 MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, set_state),
3053
3054 MYSQLND_METHOD(mysqlnd_conn_data, simple_command),
3055 MYSQLND_METHOD(mysqlnd_conn_data, simple_command_handle_response),
3056 MYSQLND_METHOD(mysqlnd_conn_data, restart_psession),
3057 MYSQLND_METHOD(mysqlnd_conn_data, end_psession),
3058 MYSQLND_METHOD(mysqlnd_conn_data, send_close),
3059
3060 MYSQLND_METHOD(mysqlnd_conn_data, ssl_set),
3061 mysqlnd_result_init,
3062 MYSQLND_METHOD(mysqlnd_conn_data, set_autocommit),
3063 MYSQLND_METHOD(mysqlnd_conn_data, tx_commit),
3064 MYSQLND_METHOD(mysqlnd_conn_data, tx_rollback),
3065 MYSQLND_METHOD(mysqlnd_conn_data, tx_begin),
3066 MYSQLND_METHOD(mysqlnd_conn_data, tx_commit_or_rollback),
3067 MYSQLND_METHOD(mysqlnd_conn_data, tx_cor_options_to_string),
3068 MYSQLND_METHOD(mysqlnd_conn_data, tx_savepoint),
3069 MYSQLND_METHOD(mysqlnd_conn_data, tx_savepoint_release),
3070
3071 MYSQLND_METHOD(mysqlnd_conn_data, local_tx_start),
3072 MYSQLND_METHOD(mysqlnd_conn_data, local_tx_end),
3073 MYSQLND_METHOD(mysqlnd_conn_data, execute_init_commands),
3074 MYSQLND_METHOD(mysqlnd_conn_data, get_updated_connect_flags),
3075 MYSQLND_METHOD(mysqlnd_conn_data, connect_handshake),
3076 MYSQLND_METHOD(mysqlnd_conn_data, simple_command_send_request),
3077 MYSQLND_METHOD(mysqlnd_conn_data, fetch_auth_plugin_by_name),
3078
3079 MYSQLND_METHOD(mysqlnd_conn_data, set_client_option_2d),
3080
3081 MYSQLND_METHOD(mysqlnd_conn_data, negotiate_client_api_capabilities),
3082 MYSQLND_METHOD(mysqlnd_conn_data, get_client_api_capabilities)
3083 MYSQLND_CLASS_METHODS_END;
3084
3085
3086
3087 static MYSQLND *
3088 MYSQLND_METHOD(mysqlnd_conn, clone_object)(MYSQLND * const conn)
3089 {
3090 MYSQLND * ret;
3091 DBG_ENTER("mysqlnd_conn::get_reference");
3092 ret = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory).clone_connection_object(conn);
3093 DBG_RETURN(ret);
3094 }
3095
3096
3097
3098
3099 static void
3100 MYSQLND_METHOD_PRIVATE(mysqlnd_conn, dtor)(MYSQLND * conn)
3101 {
3102 DBG_ENTER("mysqlnd_conn::dtor");
3103 DBG_INF_FMT("conn=%llu", conn->data->thread_id);
3104
3105 conn->data->m->free_reference(conn->data);
3106
3107 mnd_pefree(conn, conn->persistent);
3108
3109 DBG_VOID_RETURN;
3110 }
3111
3112
3113
3114
3115 static enum_func_status
3116 MYSQLND_METHOD(mysqlnd_conn, close)(MYSQLND * conn_handle, enum_connection_close_type close_type)
3117 {
3118 size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_methods, close);
3119 MYSQLND_CONN_DATA * conn = conn_handle->data;
3120 enum_func_status ret = FAIL;
3121
3122 DBG_ENTER("mysqlnd_conn::close");
3123 DBG_INF_FMT("conn=%llu", conn->thread_id);
3124
3125 if (PASS == conn->m->local_tx_start(conn, this_func)) {
3126 if (CONN_GET_STATE(conn) >= CONN_READY) {
3127 static enum_mysqlnd_collected_stats close_type_to_stat_map[MYSQLND_CLOSE_LAST] = {
3128 STAT_CLOSE_EXPLICIT,
3129 STAT_CLOSE_IMPLICIT,
3130 STAT_CLOSE_DISCONNECT
3131 };
3132 MYSQLND_INC_CONN_STATISTIC(conn->stats, close_type_to_stat_map[close_type]);
3133 }
3134
3135
3136
3137
3138
3139 ret = conn->m->send_close(conn);
3140
3141
3142 conn->m->local_tx_end(conn, this_func, ret);
3143
3144 conn_handle->m->dtor(conn_handle);
3145 }
3146 DBG_RETURN(ret);
3147 }
3148
3149
3150
3151 MYSQLND_CLASS_METHODS_START(mysqlnd_conn)
3152 MYSQLND_METHOD(mysqlnd_conn, connect),
3153 MYSQLND_METHOD(mysqlnd_conn, clone_object),
3154 MYSQLND_METHOD_PRIVATE(mysqlnd_conn, dtor),
3155 MYSQLND_METHOD(mysqlnd_conn, close)
3156 MYSQLND_CLASS_METHODS_END;
3157
3158
3159
3160 PHPAPI MYSQLND *
3161 mysqlnd_init(unsigned int flags, zend_bool persistent)
3162 {
3163 MYSQLND * ret;
3164 DBG_ENTER("mysqlnd_init");
3165 ret = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory).get_connection(persistent);
3166 if (ret && ret->data) {
3167 ret->data->m->negotiate_client_api_capabilities(ret->data, flags);
3168 }
3169 DBG_RETURN(ret);
3170 }
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180