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