php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
mysqlnd_wireprotocol.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Andrey Hristov <andrey@php.net> |
14 | Ulf Wendel <uw@php.net> |
15 +----------------------------------------------------------------------+
16*/
17
18#include "php.h"
19#include "mysqlnd.h"
20#include "mysqlnd_connection.h"
21#include "mysqlnd_ps.h"
22#include "mysqlnd_priv.h"
24#include "mysqlnd_statistics.h"
25#include "mysqlnd_debug.h"
26
27#define BAIL_IF_NO_MORE_DATA \
28 if (UNEXPECTED((size_t)(p - begin) > packet->header.size)) { \
29 php_error_docref(NULL, E_WARNING, "Premature end of data (mysqlnd_wireprotocol.c:%u)", __LINE__); \
30 goto premature_end; \
31 } \
32
33
34static const char *unknown_sqlstate= "HY000";
35const char * const mysqlnd_empty_string = "";
36
37/* Used in mysqlnd_debug.c */
38const char mysqlnd_read_header_name[] = "mysqlnd_read_header";
39const char mysqlnd_read_body_name[] = "mysqlnd_read_body";
40
41#define ERROR_MARKER 0xFF
42#define EODATA_MARKER 0xFE
43
44#define MARIADB_RPL_VERSION_HACK "5.5.5-"
45
46/* {{{ mysqlnd_command_to_text */
47const char * const mysqlnd_command_to_text[COM_END] =
48{
49 "SLEEP", "QUIT", "INIT_DB", "QUERY", "FIELD_LIST",
50 "CREATE_DB", "DROP_DB", "REFRESH", "SHUTDOWN", "STATISTICS",
51 "PROCESS_INFO", "CONNECT", "PROCESS_KILL", "DEBUG", "PING",
52 "TIME", "DELAYED_INSERT", "CHANGE_USER", "BINLOG_DUMP",
53 "TABLE_DUMP", "CONNECT_OUT", "REGISTER_SLAVE",
54 "STMT_PREPARE", "STMT_EXECUTE", "STMT_SEND_LONG_DATA", "STMT_CLOSE",
55 "STMT_RESET", "SET_OPTION", "STMT_FETCH", "DAEMON", "BINLOG_DUMP_GTID",
56 "RESET_CONNECTION"
57};
58/* }}} */
59
60
61
62static enum_mysqlnd_collected_stats packet_type_to_statistic_byte_count[PROT_LAST] =
63{
74};
75
76static enum_mysqlnd_collected_stats packet_type_to_statistic_packet_count[PROT_LAST] =
77{
88};
89
90
91/* {{{ php_mysqlnd_net_field_length
92 Get next field's length */
95{
96 const zend_uchar *p= (const zend_uchar *)*packet;
97
98 if (*p < 251) {
99 (*packet)++;
100 return (zend_ulong) *p;
101 }
102
103 switch (*p) {
104 case 251:
105 (*packet)++;
106 return MYSQLND_NULL_LENGTH;
107 case 252:
108 (*packet) += 3;
109 return (zend_ulong) uint2korr(p+1);
110 case 253:
111 (*packet) += 4;
112 return (zend_ulong) uint3korr(p+1);
113 default:
114 (*packet) += 9;
115 return (zend_ulong) uint4korr(p+1);
116 }
117}
118/* }}} */
119
120
121/* {{{ php_mysqlnd_net_field_length_ll
122 Get next field's length */
123uint64_t
125{
126 const zend_uchar *p = (zend_uchar *)*packet;
127
128 if (*p < 251) {
129 (*packet)++;
130 return (uint64_t) *p;
131 }
132
133 switch (*p) {
134 case 251:
135 (*packet)++;
136 return (uint64_t) MYSQLND_NULL_LENGTH;
137 case 252:
138 (*packet) += 3;
139 return (uint64_t) uint2korr(p + 1);
140 case 253:
141 (*packet) += 4;
142 return (uint64_t) uint3korr(p + 1);
143 default:
144 (*packet) += 9;
145 return (uint64_t) uint8korr(p + 1);
146 }
147}
148/* }}} */
149
150
151/* {{{ php_mysqlnd_net_store_length */
153php_mysqlnd_net_store_length(zend_uchar *packet, const uint64_t length)
154{
155 if (length < (uint64_t) L64(251)) {
156 *packet = (zend_uchar) length;
157 return packet + 1;
158 }
159
160 if (length < (uint64_t) L64(65536)) {
161 *packet++ = 252;
162 int2store(packet,(unsigned int) length);
163 return packet + 2;
164 }
165
166 if (length < (uint64_t) L64(16777216)) {
167 *packet++ = 253;
168 int3store(packet,(zend_ulong) length);
169 return packet + 3;
170 }
171 *packet++ = 254;
172 int8store(packet, length);
173 return packet + 8;
174}
175/* }}} */
176
177
178/* {{{ php_mysqlnd_net_store_length_size */
179size_t
181{
182 if (length < (uint64_t) L64(251)) {
183 return 1;
184 }
185 if (length < (uint64_t) L64(65536)) {
186 return 3;
187 }
188 if (length < (uint64_t) L64(16777216)) {
189 return 4;
190 }
191 return 9;
192}
193/* }}} */
194
195
196/* {{{ php_mysqlnd_read_error_from_line */
197static enum_func_status
198php_mysqlnd_read_error_from_line(const zend_uchar * const buf, const size_t buf_len,
199 char *error, const size_t error_buf_len,
200 unsigned int *error_no, char *sqlstate)
201{
202 const zend_uchar *p = buf;
203 size_t error_msg_len = 0;
204
205 DBG_ENTER("php_mysqlnd_read_error_from_line");
206
208 memcpy(sqlstate, unknown_sqlstate, MYSQLND_SQLSTATE_LENGTH);
209
210 if (buf_len > 2) {
211 *error_no = uint2korr(p);
212 p+= 2;
213 /*
214 sqlstate is following. No need to check for buf_left_len as we checked > 2 above,
215 if it was >=2 then we would need a check
216 */
217 if (*p == '#') {
218 ++p;
219 if ((buf_len - (p - buf)) >= MYSQLND_SQLSTATE_LENGTH) {
222 } else {
223 goto end;
224 }
225 }
226 if ((buf_len - (p - buf)) > 0) {
227 error_msg_len = MIN((int)((buf_len - (p - buf))), (int) (error_buf_len - 1));
228 memcpy(error, p, error_msg_len);
229 }
230 }
231end:
233 error[error_msg_len]= '\0';
234
236}
237/* }}} */
238
239
240/* {{{ mysqlnd_read_header */
241static enum_func_status
242mysqlnd_read_header(MYSQLND_PFC * pfc, MYSQLND_VIO * vio, MYSQLND_PACKET_HEADER * header,
243 MYSQLND_STATS * conn_stats, MYSQLND_ERROR_INFO * error_info)
244{
246
247 DBG_ENTER(mysqlnd_read_header_name);
248 DBG_INF_FMT("compressed=%u", pfc->data->compressed);
249 if (FAIL == pfc->data->m.receive(pfc, vio, buffer, MYSQLND_HEADER_SIZE, conn_stats, error_info)) {
251 }
252
253 header->size = uint3korr(buffer);
254 header->packet_no = uint1korr(buffer + 3);
255
256 DBG_INF_FMT("HEADER: prot_packet_no=%u size=%3zu", header->packet_no, header->size);
260
261 if (pfc->data->compressed || pfc->data->packet_no == header->packet_no) {
262 /*
263 Have to increase the number, so we can send correct number back. It will
264 round at 255 as this is unsigned char. The server needs this for simple
265 flow control checking.
266 */
267 pfc->data->packet_no++;
269 }
270 // @see https://dev.mysql.com/worklog/task/?id=12999
271 if (header->size > 0) {
273 if ((PASS == pfc->data->m.receive(pfc, vio, buf, header->size, conn_stats, error_info)) && buf[0] == ERROR_MARKER) {
274 php_mysqlnd_read_error_from_line(buf + 1, header->size - 1,
275 error_info->error, sizeof(error_info->error),
276 &error_info->error_no, error_info->sqlstate
277 );
278 mnd_efree(buf);
280 }
281 mnd_efree(buf);
282 }
283
284 DBG_ERR_FMT("Logical link: packets out of order. Expected %u received %u. Packet size=%zu",
285 pfc->data->packet_no, header->packet_no, header->size);
286
287 php_error(E_WARNING, "Packets out of order. Expected %u received %u. Packet size=%zu",
288 pfc->data->packet_no, header->packet_no, header->size);
290}
291/* }}} */
292
293
294/* {{{ mysqlnd_read_packet_header_and_body */
295static enum_func_status
296mysqlnd_read_packet_header_and_body(MYSQLND_PACKET_HEADER * packet_header,
297 MYSQLND_PFC * pfc,
298 MYSQLND_VIO * vio,
299 MYSQLND_STATS * stats,
300 MYSQLND_ERROR_INFO * error_info,
301 MYSQLND_CONNECTION_STATE * connection_state,
302 zend_uchar * const buf, const size_t buf_size,
303 const char * const packet_type_as_text,
304 enum mysqlnd_packet_type packet_type)
305{
306 DBG_ENTER("mysqlnd_read_packet_header_and_body");
307 DBG_INF_FMT("buf=%p size=%zu", buf, buf_size);
308 if (FAIL == mysqlnd_read_header(pfc, vio, packet_header, stats, error_info)) {
309 SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
310 if (error_info->error_no == 0) {
312 }
313 DBG_ERR_FMT("Can't read %s's header", packet_type_as_text);
315 }
316 if (buf_size < packet_header->size) {
317 DBG_ERR_FMT("Packet buffer %zu wasn't big enough %zu, %zu bytes will be unread",
318 buf_size, packet_header->size, packet_header->size - buf_size);
319 SET_CLIENT_ERROR(error_info, CR_INVALID_BUFFER_USE, UNKNOWN_SQLSTATE, "Packet buffer wasn't big enough; as a workaround consider increasing value of net_cmd_buffer_size");
321 }
322 if (FAIL == pfc->data->m.receive(pfc, vio, buf, packet_header->size, stats, error_info)) {
323 SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
325 DBG_ERR_FMT("Empty '%s' packet body", packet_type_as_text);
327 }
328 MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, packet_type_to_statistic_byte_count[packet_type],
329 MYSQLND_HEADER_SIZE + packet_header->size,
330 packet_type_to_statistic_packet_count[packet_type],
331 1);
333}
334/* }}} */
335
336
337/* {{{ php_mysqlnd_greet_read */
338static enum_func_status
339php_mysqlnd_greet_read(MYSQLND_CONN_DATA * conn, void * _packet)
340{
341 const zend_uchar * pad_start = NULL;
342 MYSQLND_PACKET_GREET *packet= (MYSQLND_PACKET_GREET *) _packet;
343 MYSQLND_ERROR_INFO * error_info = conn->error_info;
344 MYSQLND_PFC * pfc = conn->protocol_frame_codec;
345 MYSQLND_VIO * vio = conn->vio;
346 MYSQLND_STATS * stats = conn->stats;
347 MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
348 const size_t buf_len = pfc->cmd_buffer.length;
349 zend_uchar * const buf = (zend_uchar *) pfc->cmd_buffer.buffer;
350 const zend_uchar * p = buf;
351 const zend_uchar * const begin = buf;
352
353 DBG_ENTER("php_mysqlnd_greet_read");
354
355 if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "greeting", PROT_GREET_PACKET)) {
357 }
359
360 packet->authentication_plugin_data.s = packet->intern_auth_plugin_data;
361 packet->authentication_plugin_data.l = sizeof(packet->intern_auth_plugin_data);
362
363 packet->protocol_version = uint1korr(p);
364 p++;
366
367 if (ERROR_MARKER == packet->protocol_version) {
368 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
369 packet->error, sizeof(packet->error),
370 &packet->error_no, packet->sqlstate
371 );
372 /*
373 The server doesn't send sqlstate in the greet packet.
374 It's a bug#26426 , so we have to set it correctly ourselves.
375 It's probably "Too many connections, which has SQL state 08004".
376 */
377 if (packet->error_no == 1040) {
378 memcpy(packet->sqlstate, "08004", MYSQLND_SQLSTATE_LENGTH);
379 }
381 }
382
383 /* MariaDB always sends 5.5.5 before version string: 5.5.5 was never released,
384 so just ignore it */
385 if (!strncmp((char *) p, MARIADB_RPL_VERSION_HACK, sizeof(MARIADB_RPL_VERSION_HACK) - 1)) {
386 p += sizeof(MARIADB_RPL_VERSION_HACK) - 1;
387 }
388
389 packet->server_version = estrdup((char *)p);
390 p+= strlen(packet->server_version) + 1; /* eat the '\0' */
392
393 packet->thread_id = uint4korr(p);
394 p+=4;
396
397 memcpy(packet->authentication_plugin_data.s, p, SCRAMBLE_LENGTH_323);
400
401 /* pad1 */
402 p++;
404
405 packet->server_capabilities = uint2korr(p);
406 p+= 2;
408 DBG_INF_FMT("4.1 server_caps=%u\n", (uint32_t) packet->server_capabilities);
409
410 packet->charset_no = uint1korr(p);
411 p++;
413
414 packet->server_status = uint2korr(p);
415 p+= 2;
417
418 /* pad2 */
419 pad_start = p;
420 p+= 13;
422
423 if ((size_t) (p - buf) < packet->header.size) {
424 /* auth_plugin_data is split into two parts */
425 memcpy(packet->authentication_plugin_data.s + SCRAMBLE_LENGTH_323, p, SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
427 p++; /* 0x0 at the end of the scramble and thus last byte in the packet in 5.1 and previous */
428 } else {
429 packet->pre41 = TRUE;
430 }
431
432 /* Is this a 5.5+ server ? */
433 if ((size_t) (p - buf) < packet->header.size) {
434 /* backtrack one byte, the 0x0 at the end of the scramble in 5.1 and previous */
435 p--;
436
437 /* Additional 16 bits for server capabilities */
438 DBG_INF_FMT("additional 5.5+ caps=%u\n", (uint32_t) uint2korr(pad_start));
439 packet->server_capabilities |= ((uint32_t) uint2korr(pad_start)) << 16;
440 /* And a length of the server scramble in one byte */
441 packet->authentication_plugin_data.l = uint1korr(pad_start + 2);
442 if (packet->authentication_plugin_data.l > SCRAMBLE_LENGTH) {
443 /* more data*/
444 char * new_auth_plugin_data = emalloc(packet->authentication_plugin_data.l);
445
446 /* copy what we already have */
447 memcpy(new_auth_plugin_data, packet->authentication_plugin_data.s, SCRAMBLE_LENGTH);
448 /* add additional scramble data 5.5+ sent us */
449 memcpy(new_auth_plugin_data + SCRAMBLE_LENGTH, p, packet->authentication_plugin_data.l - SCRAMBLE_LENGTH);
450 p+= (packet->authentication_plugin_data.l - SCRAMBLE_LENGTH);
451 packet->authentication_plugin_data.s = new_auth_plugin_data;
452 }
453 }
454
455 if (packet->server_capabilities & CLIENT_PLUGIN_AUTH) {
457 /* The server is 5.5.x and supports authentication plugins */
458 size_t remaining_size = packet->header.size - (size_t)(p - buf);
459 if (remaining_size == 0) {
460 /* Might be better to fail but this will fail anyway */
461 packet->auth_protocol = estrdup("");
462 } else {
463 /* Check if NUL present */
464 char *null_terminator = memchr(p, '\0', remaining_size);
465 size_t auth_protocol_len;
466 if (null_terminator) {
467 /* If present, do basically estrdup */
468 auth_protocol_len = null_terminator - (char *)p;
469 } else {
470 /* If not present, copy the rest of the buffer */
471 auth_protocol_len = remaining_size;
472 }
473 char *auth_protocol = emalloc(auth_protocol_len + 1);
474 memcpy(auth_protocol, p, auth_protocol_len);
475 auth_protocol[auth_protocol_len] = '\0';
476 packet->auth_protocol = auth_protocol;
477
478 p += auth_protocol_len;
479 if (null_terminator) {
480 p++;
481 }
482 }
483 }
484
485 DBG_INF_FMT("proto=%u server=%s thread_id=%u",
486 packet->protocol_version, packet->server_version, packet->thread_id);
487
488 DBG_INF_FMT("server_capabilities=%u charset_no=%u server_status=%i auth_protocol=%s scramble_length=%zu",
489 packet->server_capabilities, packet->charset_no, packet->server_status,
490 packet->auth_protocol? packet->auth_protocol:"n/a", packet->authentication_plugin_data.l);
491
493premature_end:
494 DBG_ERR_FMT("GREET packet %zu bytes shorter than expected", p - begin - packet->header.size);
495 php_error_docref(NULL, E_WARNING, "GREET packet %zu bytes shorter than expected",
496 p - begin - packet->header.size);
498}
499/* }}} */
500
501
502/* {{{ php_mysqlnd_greet_free_mem */
503static
504void php_mysqlnd_greet_free_mem(void * _packet)
505{
507 if (p->server_version) {
508 efree(p->server_version);
509 p->server_version = NULL;
510 }
511 if (p->authentication_plugin_data.s && p->authentication_plugin_data.s != p->intern_auth_plugin_data) {
512 efree(p->authentication_plugin_data.s);
513 p->authentication_plugin_data.s = NULL;
514 }
515 if (p->auth_protocol) {
516 efree(p->auth_protocol);
517 p->auth_protocol = NULL;
518 }
519}
520/* }}} */
521
522
523#define AUTH_WRITE_BUFFER_LEN (MYSQLND_HEADER_SIZE + MYSQLND_MAX_ALLOWED_USER_LEN + SCRAMBLE_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1 + 4096)
524
525/* {{{ php_mysqlnd_auth_write */
526static
527size_t php_mysqlnd_auth_write(MYSQLND_CONN_DATA * conn, void * _packet)
528{
530 zend_uchar *p = buffer + MYSQLND_HEADER_SIZE; /* start after the header */
531 size_t len;
532 MYSQLND_PACKET_AUTH * packet= (MYSQLND_PACKET_AUTH *) _packet;
533 MYSQLND_ERROR_INFO * error_info = conn->error_info;
534 MYSQLND_PFC * pfc = conn->protocol_frame_codec;
535 MYSQLND_VIO * vio = conn->vio;
536 MYSQLND_STATS * stats = conn->stats;
537 MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
538
539 DBG_ENTER("php_mysqlnd_auth_write");
540
541 if (!packet->is_change_user_packet) {
542 int4store(p, packet->client_flags);
543 p+= 4;
544
545 int4store(p, packet->max_packet_size);
546 p+= 4;
547
548 int1store(p, packet->charset_no);
549 p++;
550
551 memset(p, 0, 23); /* filler */
552 p+= 23;
553 }
554
555 if (packet->send_auth_data || packet->is_change_user_packet) {
557 p = zend_mempcpy(p, packet->user, len);
558 *p++ = '\0';
559
560 /* defensive coding */
561 if (packet->auth_data == NULL) {
562 packet->auth_data_len = 0;
563 }
564 if (packet->auth_data_len > 0xFF) {
565 const char * const msg = "Authentication data too long. "
566 "Won't fit into the buffer and will be truncated. Authentication will thus fail";
569 DBG_RETURN(0);
570 }
571
572 int1store(p, (int8_t)packet->auth_data_len);
573 ++p;
575 if (sizeof(buffer) < (packet->auth_data_len + (p - buffer))) {
576 DBG_ERR("the stack buffer was not enough!!");
577 DBG_RETURN(0);
578 }
579 if (packet->auth_data_len) {
580 p = zend_mempcpy(p, packet->auth_data, packet->auth_data_len);
581 }
582
583 if (packet->db_len > 0) {
584 /* CLIENT_CONNECT_WITH_DB should have been set */
585 size_t real_db_len = MIN(MYSQLND_MAX_ALLOWED_DB_LEN, packet->db_len);
586 p = zend_mempcpy(p, packet->db, real_db_len);
587 *p++= '\0';
588 } else if (packet->is_change_user_packet) {
589 *p++= '\0';
590 }
591 /* no \0 for no DB */
592
593 if (packet->is_change_user_packet) {
594 if (packet->charset_no) {
595 int2store(p, packet->charset_no);
596 p+= 2;
597 }
598 }
599
600 if (packet->auth_plugin_name) {
601 len = MIN(strlen(packet->auth_plugin_name), sizeof(buffer) - (p - buffer) - 1);
602 p = zend_mempcpy(p, packet->auth_plugin_name, len);
603 *p++= '\0';
604 }
605
606 if (packet->connect_attr && zend_hash_num_elements(packet->connect_attr)) {
607 size_t ca_payload_len = 0;
608
609 {
611 zval * entry_value;
612 ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(packet->connect_attr, key, entry_value) {
613 if (key) { /* HASH_KEY_IS_STRING */
614 size_t value_len = Z_STRLEN_P(entry_value);
615
617 ca_payload_len += ZSTR_LEN(key);
618 ca_payload_len += php_mysqlnd_net_store_length_size(value_len);
619 ca_payload_len += value_len;
620 }
622 }
623
624 if (sizeof(buffer) >= (ca_payload_len + php_mysqlnd_net_store_length_size(ca_payload_len) + (p - buffer))) {
625 p = php_mysqlnd_net_store_length(p, ca_payload_len);
626
627 {
629 zval * entry_value;
630 ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(packet->connect_attr, key, entry_value) {
631 if (key) { /* HASH_KEY_IS_STRING */
632 size_t value_len = Z_STRLEN_P(entry_value);
633
634 /* copy key */
636 p = zend_mempcpy(p, ZSTR_VAL(key), ZSTR_LEN(key));
637 /* copy value */
638 p = php_mysqlnd_net_store_length(p, value_len);
639 p = zend_mempcpy(p, Z_STRVAL_P(entry_value), value_len);
640 }
642 }
643 } else {
644 /* cannot put the data - skip */
645 }
646 }
647 }
648 if (packet->is_change_user_packet) {
650 const MYSQLND_CSTRING payload = {(char*) buffer + MYSQLND_HEADER_SIZE, p - (buffer + MYSQLND_HEADER_SIZE)};
651 const unsigned int silent = packet->silent;
652
653 ret = conn->command->change_user(conn, payload, silent);
655 } else {
656 /*
657 The auth handshake packet has no command in it. Thus we can't go over conn->command directly.
658 Well, we can have a command->no_command(conn, payload)
659 */
660 const size_t sent = pfc->data->m.send(pfc, vio, buffer, p - buffer - MYSQLND_HEADER_SIZE, stats, error_info);
661 if (!sent) {
662 SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
663 }
664 DBG_RETURN(sent);
665 }
666}
667/* }}} */
668
669
670/* {{{ php_mysqlnd_auth_response_read */
671static enum_func_status
672php_mysqlnd_auth_response_read(MYSQLND_CONN_DATA * conn, void * _packet)
673{
675 MYSQLND_ERROR_INFO * error_info = conn->error_info;
676 MYSQLND_PFC * pfc = conn->protocol_frame_codec;
677 MYSQLND_VIO * vio = conn->vio;
678 MYSQLND_STATS * stats = conn->stats;
679 MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
680 const size_t buf_len = pfc->cmd_buffer.length;
681 zend_uchar * const buf = (zend_uchar *) pfc->cmd_buffer.buffer;
682 const zend_uchar * p = buf;
683 const zend_uchar * const begin = buf;
684
685 DBG_ENTER("php_mysqlnd_auth_response_read");
686
687 if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "OK", PROT_OK_PACKET)) {
689 }
691
692 /* Should be always 0x0 or ERROR_MARKER for error */
693 packet->response_code = uint1korr(p);
694 p++;
696
697 if (ERROR_MARKER == packet->response_code) {
698 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
699 packet->error, sizeof(packet->error),
700 &packet->error_no, packet->sqlstate
701 );
703 }
704 if (0xFE == packet->response_code) {
705 /* Authentication Switch Response */
706 if (packet->header.size > (size_t) (p - buf)) {
707 packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE);
708 packet->new_auth_protocol_len = strlen(packet->new_auth_protocol);
709 p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */
710
711 packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf);
712 if (packet->new_auth_protocol_data_len) {
713 packet->new_auth_protocol_data = mnd_emalloc(packet->new_auth_protocol_data_len);
714 memcpy(packet->new_auth_protocol_data, p, packet->new_auth_protocol_data_len);
715 }
716 DBG_INF_FMT("The server requested switching auth plugin to : %s", packet->new_auth_protocol);
717 DBG_INF_FMT("Server salt : [%zu][%.*s]", packet->new_auth_protocol_data_len, (int) packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
718 }
719 } else {
720 zend_ulong net_len;
721 /* Everything was fine! */
722 packet->affected_rows = php_mysqlnd_net_field_length_ll(&p);
724
725 packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p);
727
728 packet->server_status = uint2korr(p);
729 p+= 2;
731
732 packet->warning_count = uint2korr(p);
733 p+= 2;
735
736 /* There is a message */
737 if (packet->header.size > (size_t) (p - buf) && (net_len = php_mysqlnd_net_field_length(&p))) {
738 /* p can get past packet size when getting field length so it needs to be checked first
739 * and after that it can be checked that the net_len is not greater than the packet size */
740 if ((p - buf) > packet->header.size || packet->header.size - (p - buf) < net_len) {
741 DBG_ERR_FMT("OK packet message length is past the packet size");
742 php_error_docref(NULL, E_WARNING, "OK packet message length is past the packet size");
744 }
745 packet->message_len = net_len;
746 packet->message = mnd_pestrndup((char *)p, packet->message_len, FALSE);
747 } else {
748 packet->message = NULL;
749 packet->message_len = 0;
750 }
751
752 DBG_INF_FMT("OK packet: aff_rows=%" PRIu64 " last_ins_id=%" PRIu64 " server_status=%u warnings=%u",
753 packet->affected_rows, packet->last_insert_id, packet->server_status,
754 packet->warning_count);
755 }
756
758premature_end:
759 DBG_ERR_FMT("OK packet %zu bytes shorter than expected", p - begin - packet->header.size);
760 php_error_docref(NULL, E_WARNING, "AUTH_RESPONSE packet %zu bytes shorter than expected",
761 p - begin - packet->header.size);
763}
764/* }}} */
765
766
767/* {{{ php_mysqlnd_auth_response_free_mem */
768static void
769php_mysqlnd_auth_response_free_mem(void * _packet)
770{
772 if (p->message) {
773 mnd_efree(p->message);
774 p->message = NULL;
775 }
776 if (p->new_auth_protocol) {
777 mnd_efree(p->new_auth_protocol);
778 p->new_auth_protocol = NULL;
779 }
780 p->new_auth_protocol_len = 0;
781
782 if (p->new_auth_protocol_data) {
783 mnd_efree(p->new_auth_protocol_data);
784 p->new_auth_protocol_data = NULL;
785 }
786 p->new_auth_protocol_data_len = 0;
787}
788/* }}} */
789
790
791/* {{{ php_mysqlnd_change_auth_response_write */
792static size_t
793php_mysqlnd_change_auth_response_write(MYSQLND_CONN_DATA * conn, void * _packet)
794{
796 MYSQLND_ERROR_INFO * error_info = conn->error_info;
797 MYSQLND_PFC * pfc = conn->protocol_frame_codec;
798 MYSQLND_VIO * vio = conn->vio;
799 MYSQLND_STATS * stats = conn->stats;
800 MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
801 size_t total_packet_size = packet->auth_data_len + MYSQLND_HEADER_SIZE;
802 zend_uchar * const buffer = pfc->cmd_buffer.length >= total_packet_size? pfc->cmd_buffer.buffer : mnd_emalloc(total_packet_size);
803 zend_uchar * p = buffer + MYSQLND_HEADER_SIZE; /* start after the header */
804
805 DBG_ENTER("php_mysqlnd_change_auth_response_write");
806
807 if (packet->auth_data_len) {
808 p = zend_mempcpy(p, packet->auth_data, packet->auth_data_len);
809 }
810
811 {
812 /*
813 The auth handshake packet has no command in it. Thus we can't go over conn->command directly.
814 Well, we can have a command->no_command(conn, payload)
815 */
816 const size_t sent = pfc->data->m.send(pfc, vio, buffer, p - buffer - MYSQLND_HEADER_SIZE, stats, error_info);
817 if (buffer != pfc->cmd_buffer.buffer) {
819 }
820 if (!sent) {
821 SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
822 }
823 DBG_RETURN(sent);
824 }
825}
826/* }}} */
827
828
829/* {{{ php_mysqlnd_ok_read */
830static enum_func_status
831php_mysqlnd_ok_read(MYSQLND_CONN_DATA * conn, void * _packet)
832{
833 MYSQLND_PACKET_OK *packet= (MYSQLND_PACKET_OK *) _packet;
834 MYSQLND_ERROR_INFO * error_info = conn->error_info;
835 MYSQLND_PFC * pfc = conn->protocol_frame_codec;
836 MYSQLND_VIO * vio = conn->vio;
837 MYSQLND_STATS * stats = conn->stats;
838 MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
839 const size_t buf_len = pfc->cmd_buffer.length;
840 zend_uchar * const buf = (zend_uchar *) pfc->cmd_buffer.buffer;
841 const zend_uchar * p = buf;
842 const zend_uchar * const begin = buf;
843 zend_ulong net_len;
844
845 DBG_ENTER("php_mysqlnd_ok_read");
846
847 if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "OK", PROT_OK_PACKET)) {
849 }
851
852 /* Should be always 0x0 or ERROR_MARKER for error */
853 packet->field_count = uint1korr(p);
854 p++;
856
857 if (ERROR_MARKER == packet->field_count) {
858 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
859 packet->error, sizeof(packet->error),
860 &packet->error_no, packet->sqlstate
861 );
863 }
864 /* Everything was fine! */
865 packet->affected_rows = php_mysqlnd_net_field_length_ll(&p);
867
868 packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p);
870
871 packet->server_status = uint2korr(p);
872 p+= 2;
874
875 packet->warning_count = uint2korr(p);
876 p+= 2;
878
879 /* There is a message */
880 if (packet->header.size > (size_t) (p - buf) && (net_len = php_mysqlnd_net_field_length(&p))) {
881 packet->message_len = MIN(net_len, buf_len - (p - begin));
882 packet->message = mnd_pestrndup((char *)p, packet->message_len, FALSE);
883 } else {
884 packet->message = NULL;
885 packet->message_len = 0;
886 }
887
888 DBG_INF_FMT("OK packet: aff_rows=%" PRIu64 " last_ins_id=%" PRIu64 " server_status=%u warnings=%u",
889 packet->affected_rows, packet->last_insert_id, packet->server_status,
890 packet->warning_count);
891
893
895premature_end:
896 DBG_ERR_FMT("OK packet %zu bytes shorter than expected", p - begin - packet->header.size);
897 php_error_docref(NULL, E_WARNING, "OK packet %zu bytes shorter than expected",
898 p - begin - packet->header.size);
900}
901/* }}} */
902
903
904/* {{{ php_mysqlnd_ok_free_mem */
905static void
906php_mysqlnd_ok_free_mem(void * _packet)
907{
909 if (p->message) {
910 mnd_efree(p->message);
911 p->message = NULL;
912 }
913}
914/* }}} */
915
916
917/* {{{ php_mysqlnd_eof_read */
918static enum_func_status
919php_mysqlnd_eof_read(MYSQLND_CONN_DATA * conn, void * _packet)
920{
921 /*
922 EOF packet is since 4.1 five bytes long,
923 but we can get also an error, make it bigger.
924
925 Error : error_code + '#' + sqlstate + MYSQLND_ERRMSG_SIZE
926 */
927 MYSQLND_PACKET_EOF *packet= (MYSQLND_PACKET_EOF *) _packet;
928 MYSQLND_ERROR_INFO * error_info = conn->error_info;
929 MYSQLND_PFC * pfc = conn->protocol_frame_codec;
930 MYSQLND_VIO * vio = conn->vio;
931 MYSQLND_STATS * stats = conn->stats;
932 MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
933 const size_t buf_len = pfc->cmd_buffer.length;
934 zend_uchar * const buf = (zend_uchar *) pfc->cmd_buffer.buffer;
935 const zend_uchar * p = buf;
936 const zend_uchar * const begin = buf;
937
938 DBG_ENTER("php_mysqlnd_eof_read");
939
940 if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "EOF", PROT_EOF_PACKET)) {
942 }
944
945 /* Should be always EODATA_MARKER */
946 packet->field_count = uint1korr(p);
947 p++;
949
950 if (ERROR_MARKER == packet->field_count) {
951 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
952 packet->error, sizeof(packet->error),
953 &packet->error_no, packet->sqlstate
954 );
956 }
957
958 /*
959 4.1 sends 1 byte EOF packet after metadata of
960 PREPARE/EXECUTE but 5 bytes after the result. This is not
961 according to the Docs@Forge!!!
962 */
963 if (packet->header.size > 1) {
964 packet->warning_count = uint2korr(p);
965 p+= 2;
967
968 packet->server_status = uint2korr(p);
969 p+= 2;
971 } else {
972 packet->warning_count = 0;
973 packet->server_status = 0;
974 }
975
977
978 DBG_INF_FMT("EOF packet: fields=%u status=%u warnings=%u",
979 packet->field_count, packet->server_status, packet->warning_count);
980
982premature_end:
983 DBG_ERR_FMT("EOF packet %zu bytes shorter than expected", p - begin - packet->header.size);
984 php_error_docref(NULL, E_WARNING, "EOF packet %zu bytes shorter than expected",
985 p - begin - packet->header.size);
987}
988/* }}} */
989
990
991/* {{{ php_mysqlnd_cmd_write */
992size_t php_mysqlnd_cmd_write(MYSQLND_CONN_DATA * conn, void * _packet)
993{
994 /* Let's have some space, which we can use, if not enough, we will allocate new buffer */
996 MYSQLND_ERROR_INFO * error_info = conn->error_info;
997 MYSQLND_PFC * pfc = conn->protocol_frame_codec;
998 MYSQLND_VIO * vio = conn->vio;
999 MYSQLND_STATS * stats = conn->stats;
1000 MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
1001 size_t sent = 0;
1002
1003 DBG_ENTER("php_mysqlnd_cmd_write");
1004 /*
1005 Reset packet_no, or we will get bad handshake!
1006 Every command starts a new TX and packet numbers are reset to 0.
1007 */
1008 pfc->data->m.reset(pfc, stats, error_info);
1009
1011
1012#ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
1013 vio->data->m.consume_uneaten_data(vio, packet->command);
1014#endif
1015
1016 if (!packet->argument.s || !packet->argument.l) {
1018
1020 sent = pfc->data->m.send(pfc, vio, buffer, 1, stats, error_info);
1021 } else {
1022 size_t tmp_len = packet->argument.l + 1 + MYSQLND_HEADER_SIZE;
1023 zend_uchar *tmp, *p;
1024 tmp = (tmp_len > pfc->cmd_buffer.length)? mnd_emalloc(tmp_len):pfc->cmd_buffer.buffer;
1025 if (!tmp) {
1026 goto end;
1027 }
1028 p = tmp + MYSQLND_HEADER_SIZE; /* skip the header */
1029
1030 int1store(p, packet->command);
1031 p++;
1032
1033 memcpy(p, packet->argument.s, packet->argument.l);
1034
1035 sent = pfc->data->m.send(pfc, vio, tmp, tmp_len - MYSQLND_HEADER_SIZE, stats, error_info);
1036 if (tmp != pfc->cmd_buffer.buffer) {
1038 mnd_efree(tmp);
1039 }
1040 }
1041end:
1042 if (!sent) {
1043 SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
1044 }
1045 DBG_RETURN(sent);
1046}
1047/* }}} */
1048
1049
1050/* {{{ php_mysqlnd_rset_header_read */
1051static enum_func_status
1052php_mysqlnd_rset_header_read(MYSQLND_CONN_DATA * conn, void * _packet)
1053{
1055 MYSQLND_ERROR_INFO * error_info = conn->error_info;
1056 MYSQLND_PFC * pfc = conn->protocol_frame_codec;
1057 MYSQLND_VIO * vio = conn->vio;
1058 MYSQLND_STATS * stats = conn->stats;
1059 MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
1061 const size_t buf_len = pfc->cmd_buffer.length;
1062 zend_uchar * const buf = (zend_uchar *) pfc->cmd_buffer.buffer;
1063 const zend_uchar * p = buf;
1064 const zend_uchar * const begin = buf;
1065 size_t len;
1066
1067 DBG_ENTER("php_mysqlnd_rset_header_read");
1068
1069 if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "resultset header", PROT_RSET_HEADER_PACKET)) {
1071 }
1073
1074 /*
1075 Don't increment. First byte is ERROR_MARKER on error, but otherwise is starting byte
1076 of encoded sequence for length.
1077 */
1078 if (ERROR_MARKER == *p) {
1079 /* Error */
1080 p++;
1082 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
1083 packet->error_info.error, sizeof(packet->error_info.error),
1084 &packet->error_info.error_no, packet->error_info.sqlstate
1085 );
1087 }
1088
1089 packet->field_count = php_mysqlnd_net_field_length(&p);
1091
1092 switch (packet->field_count) {
1094 DBG_INF("LOAD LOCAL");
1095 /*
1096 First byte in the packet is the field count.
1097 Thus, the name is size - 1. And we add 1 for a trailing \0.
1098 Because we have BAIL_IF_NO_MORE_DATA before the switch, we are guaranteed
1099 that packet->header.size is > 0. Which means that len can't underflow, that
1100 would lead to 0 byte allocation but 2^32 or 2^64 bytes copied.
1101 */
1102 len = packet->header.size - 1;
1103 packet->info_or_local_file.s = mnd_emalloc(len + 1);
1104 memcpy(packet->info_or_local_file.s, p, len);
1105 packet->info_or_local_file.s[len] = '\0';
1106 packet->info_or_local_file.l = len;
1107 break;
1108 case 0x00:
1109 DBG_INF("UPSERT");
1110 packet->affected_rows = php_mysqlnd_net_field_length_ll(&p);
1112
1113 packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p);
1115
1116 packet->server_status = uint2korr(p);
1117 p+=2;
1119
1120 packet->warning_count = uint2korr(p);
1121 p+=2;
1123 /* Check for additional textual data */
1124 if (packet->header.size > (size_t) (p - buf) && (len = php_mysqlnd_net_field_length(&p))) {
1125 /* p can get past packet size when getting field length so it needs to be checked first
1126 * and after that it can be checked that the len is not greater than the packet size */
1127 if ((p - buf) > packet->header.size || packet->header.size - (p - buf) < len) {
1128 size_t local_file_name_over_read = ((p - buf) - packet->header.size) + len;
1129 DBG_ERR_FMT("RSET_HEADER packet additional data length is past %zu bytes the packet size",
1130 local_file_name_over_read);
1132 "RSET_HEADER packet additional data length is past %zu bytes the packet size",
1133 local_file_name_over_read);
1135 }
1136 packet->info_or_local_file.s = mnd_emalloc(len + 1);
1137 memcpy(packet->info_or_local_file.s, p, len);
1138 packet->info_or_local_file.s[len] = '\0';
1139 packet->info_or_local_file.l = len;
1140 }
1141 DBG_INF_FMT("affected_rows=%" PRIu64 " last_insert_id=%" PRIu64 " server_status=%u warning_count=%u",
1142 packet->affected_rows, packet->last_insert_id,
1143 packet->server_status, packet->warning_count);
1144 break;
1145 default:
1146 DBG_INF("SELECT");
1147 /* Result set */
1148 break;
1149 }
1151
1152 DBG_RETURN(ret);
1153premature_end:
1154 DBG_ERR_FMT("RSET_HEADER packet %zu bytes shorter than expected", p - begin - packet->header.size);
1155 php_error_docref(NULL, E_WARNING, "RSET_HEADER packet %zu bytes shorter than expected",
1156 p - begin - packet->header.size);
1158}
1159/* }}} */
1160
1161
1162/* {{{ php_mysqlnd_rset_header_free_mem */
1163static
1164void php_mysqlnd_rset_header_free_mem(void * _packet)
1165{
1167 DBG_ENTER("php_mysqlnd_rset_header_free_mem");
1168 mysqlnd_set_string(&p->info_or_local_file, NULL, 0);
1170}
1171/* }}} */
1172
1173#define READ_RSET_FIELD(field_name) do { \
1174 len = php_mysqlnd_net_field_length(&p); \
1175 if (UNEXPECTED(len == MYSQLND_NULL_LENGTH)) { \
1176 goto faulty_or_fake; \
1177 } else if (len != 0) { \
1178 meta->field_name = (const char *)p; \
1179 meta->field_name ## _length = len; \
1180 p += len; \
1181 total_len += len + 1; \
1182 } else { \
1183 meta->field_name = mysqlnd_empty_string; \
1184 meta->field_name ## _length = 0; \
1185 } \
1186 } while (0)
1187
1188
1189/* {{{ php_mysqlnd_rset_field_read */
1190static enum_func_status
1191php_mysqlnd_rset_field_read(MYSQLND_CONN_DATA * conn, void * _packet)
1192{
1193 /* Should be enough for the metadata of a single row */
1195 MYSQLND_ERROR_INFO * error_info = conn->error_info;
1196 MYSQLND_PFC * pfc = conn->protocol_frame_codec;
1197 MYSQLND_VIO * vio = conn->vio;
1198 MYSQLND_STATS * stats = conn->stats;
1199 MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
1200 const size_t buf_len = pfc->cmd_buffer.length;
1201 size_t total_len = 0;
1202 zend_uchar * const buf = (zend_uchar *) pfc->cmd_buffer.buffer;
1203 const zend_uchar * p = buf;
1204 const zend_uchar * const begin = buf;
1205 char *root_ptr;
1207 MYSQLND_FIELD *meta;
1208
1209 DBG_ENTER("php_mysqlnd_rset_field_read");
1210
1211 if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "field", PROT_RSET_FLD_PACKET)) {
1213 }
1214
1215 if (packet->skip_parsing) {
1217 }
1218
1220 if (ERROR_MARKER == *p) {
1221 /* Error */
1222 p++;
1224 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
1225 packet->error_info.error, sizeof(packet->error_info.error),
1226 &packet->error_info.error_no, packet->error_info.sqlstate
1227 );
1228 DBG_ERR_FMT("Server error : (%u) %s", packet->error_info.error_no, packet->error_info.error);
1230 } else if (EODATA_MARKER == *p && packet->header.size < 8) {
1231 /* Premature EOF. That should be COM_FIELD_LIST. But we don't support COM_FIELD_LIST anymore, thus this should not happen */
1232 DBG_ERR("Premature EOF. That should be COM_FIELD_LIST");
1233 php_error_docref(NULL, E_WARNING, "Premature EOF in result field metadata");
1235 }
1236
1237 meta = packet->metadata;
1238
1239 READ_RSET_FIELD(catalog);
1240 READ_RSET_FIELD(db);
1241 READ_RSET_FIELD(table);
1242 READ_RSET_FIELD(org_table);
1244 READ_RSET_FIELD(org_name);
1245
1246 /* 1 byte length */
1247 if (UNEXPECTED(12 != *p)) {
1248 DBG_ERR_FMT("Protocol error. Server sent false length. Expected 12 got %d", (int) *p);
1249 php_error_docref(NULL, E_WARNING, "Protocol error. Server sent false length. Expected 12");
1250 }
1251
1252 if ((size_t)((p - begin) + 12) > packet->header.size) {
1253 php_error_docref(NULL, E_WARNING, "Premature end of data (mysqlnd_wireprotocol.c:%u)", __LINE__);
1254 goto premature_end;
1255 }
1256
1257 p++;
1258
1259 meta->charsetnr = uint2korr(p);
1260 p += 2;
1261
1262 meta->length = uint4korr(p);
1263 p += 4;
1264
1265 meta->type = uint1korr(p);
1266 p += 1;
1267
1268 meta->flags = uint2korr(p);
1269 p += 2;
1270
1271 meta->decimals = uint1korr(p);
1272 p += 1;
1273
1274 /* 2 byte filler */
1275 p +=2;
1276
1277 /* Should we set NUM_FLAG (libmysql does it) ? */
1278 if (
1279 (meta->type <= MYSQL_TYPE_INT24 &&
1280 (meta->type != MYSQL_TYPE_TIMESTAMP || meta->length == 14 || meta->length == 8)
1281 ) || meta->type == MYSQL_TYPE_YEAR)
1282 {
1283 meta->flags |= NUM_FLAG;
1284 }
1285
1286 /* COM_FIELD_LIST is no longer supported so def should not be present */
1287 if (packet->header.size > (size_t) (p - buf) &&
1290 {
1291 DBG_ERR_FMT("Protocol error. Server sent default for unsupported field list");
1293 "Protocol error. Server sent default for unsupported field list (mysqlnd_wireprotocol.c:%u)",
1294 __LINE__);
1296 }
1297
1298 root_ptr = meta->root = packet->memory_pool->get_chunk(packet->memory_pool, total_len);
1299 meta->root_len = total_len;
1300
1301 if (EXPECTED(meta->name_length != 0)) {
1302 meta->sname = zend_string_init_interned(meta->name, meta->name_length, 0);
1303 meta->name = ZSTR_VAL(meta->sname);
1304 } else {
1305 meta->sname = ZSTR_EMPTY_ALLOC();
1306 }
1307
1308 /* Now do allocs */
1309 if (meta->catalog_length != 0) {
1310 len = meta->catalog_length;
1311 meta->catalog = memcpy(root_ptr, meta->catalog, len);
1312 *(root_ptr +=len) = '\0';
1313 root_ptr++;
1314 }
1315
1316 if (meta->db_length != 0) {
1317 len = meta->db_length;
1318 meta->db = memcpy(root_ptr, meta->db, len);
1319 *(root_ptr +=len) = '\0';
1320 root_ptr++;
1321 }
1322
1323 if (meta->table_length != 0) {
1324 len = meta->table_length;
1325 meta->table = memcpy(root_ptr, meta->table, len);
1326 *(root_ptr +=len) = '\0';
1327 root_ptr++;
1328 }
1329
1330 if (meta->org_table_length != 0) {
1331 len = meta->org_table_length;
1332 meta->org_table = memcpy(root_ptr, meta->org_table, len);
1333 *(root_ptr +=len) = '\0';
1334 root_ptr++;
1335 }
1336
1337 if (meta->org_name_length != 0) {
1338 len = meta->org_name_length;
1339 meta->org_name = memcpy(root_ptr, meta->org_name, len);
1340 *(root_ptr +=len) = '\0';
1341 root_ptr++;
1342 }
1343
1344 DBG_INF_FMT("allocing root.");
1345
1346 DBG_INF_FMT("FIELD=[%s.%s.%s]", meta->db? meta->db:"*NA*", meta->table? meta->table:"*NA*",
1347 meta->name? meta->name:"*NA*");
1348
1350
1351faulty_or_fake:
1352 DBG_ERR_FMT("Protocol error. Server sent NULL_LENGTH. The server is faulty");
1353 php_error_docref(NULL, E_WARNING, "Protocol error. Server sent NULL_LENGTH."
1354 " The server is faulty");
1356premature_end:
1357 DBG_ERR_FMT("RSET field packet %zu bytes shorter than expected", p - begin - packet->header.size);
1358 php_error_docref(NULL, E_WARNING, "Result set field packet %zu bytes "
1359 "shorter than expected", p - begin - packet->header.size);
1361}
1362/* }}} */
1363
1364/* Like SET_CLIENT_ERROR, but for packet error_info. The type is the same,
1365 * but only some parts of it are used. */
1366static void set_packet_error(
1367 MYSQLND_ERROR_INFO *info, unsigned err_no, const char *sqlstate, const char *error)
1368{
1369 info->error_no = err_no;
1370 strlcpy(info->sqlstate, sqlstate, sizeof(info->sqlstate));
1371 strlcpy(info->error, error, sizeof(info->error));
1372}
1373
1374/* {{{ php_mysqlnd_read_row_ex */
1375static enum_func_status
1376php_mysqlnd_read_row_ex(MYSQLND_PFC * pfc,
1377 MYSQLND_VIO * vio,
1378 MYSQLND_STATS * stats,
1379 MYSQLND_ERROR_INFO * error_info,
1380 MYSQLND_CONNECTION_STATE * connection_state,
1381 MYSQLND_MEMORY_POOL * pool,
1383 size_t * const data_size)
1384{
1387 zend_uchar * p = NULL;
1388 size_t prealloc_more_bytes;
1389
1390 DBG_ENTER("php_mysqlnd_read_row_ex");
1391
1392 /*
1393 To ease the process the server splits everything in packets up to 2^24 - 1.
1394 Even in the case the payload is evenly divisible by this value, the last
1395 packet will be empty, namely 0 bytes. Thus, we can read every packet and ask
1396 for next one if they have 2^24 - 1 sizes. But just read the header of a
1397 zero-length byte, don't read the body, there is no such.
1398 */
1399
1400 /*
1401 We're allocating an extra byte, as php_mysqlnd_rowp_read_text_protocol
1402 needs to be able to append a terminating \0 for atoi/atof.
1403 */
1404 prealloc_more_bytes = 1;
1405
1406 *data_size = 0;
1407 if (UNEXPECTED(FAIL == mysqlnd_read_header(pfc, vio, &header, stats, error_info))) {
1408 ret = FAIL;
1409 SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
1410 set_packet_error(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
1411 } else {
1412 /* If the packet is split in multiple chunks, allocate a temporary buffer that we can
1413 * reallocate, and only afterwards copy it to the pool when we know the final size. */
1414 zend_uchar *buf = NULL;
1415 while (header.size >= MYSQLND_MAX_PACKET_SIZE) {
1416 buf = erealloc(buf, *data_size + header.size);
1417 p = buf + *data_size;
1418 *data_size += header.size;
1419
1420 if (UNEXPECTED(PASS != (ret = pfc->data->m.receive(pfc, vio, p, header.size, stats, error_info)))) {
1421 DBG_ERR("Empty row packet body");
1422 SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
1423 set_packet_error(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
1424 efree(buf);
1426 }
1427 if (FAIL == mysqlnd_read_header(pfc, vio, &header, stats, error_info)) {
1428 efree(buf);
1430 }
1431 }
1432
1433 buffer->ptr = pool->get_chunk(pool, *data_size + header.size + prealloc_more_bytes);
1434 if (buf) {
1435 memcpy(buffer->ptr, buf, *data_size);
1436 efree(buf);
1437 }
1438 p = (zend_uchar *) buffer->ptr + *data_size;
1439 *data_size += header.size;
1440
1441 if (UNEXPECTED(PASS != (ret = pfc->data->m.receive(pfc, vio, p, header.size, stats, error_info)))) {
1442 DBG_ERR("Empty row packet body");
1443 SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
1444 set_packet_error(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
1445 }
1446 }
1447 DBG_RETURN(ret);
1448}
1449/* }}} */
1450
1451
1452/* {{{ php_mysqlnd_rowp_read_binary_protocol */
1455 const unsigned int field_count, const MYSQLND_FIELD * const fields_metadata,
1456 const bool as_int_or_float, MYSQLND_STATS * const stats)
1457{
1458 unsigned int i, j;
1459 size_t rbs = row_buffer->size;
1460 const zend_uchar * rbp = row_buffer->ptr;
1461 const zend_uchar * p = rbp;
1462 const zend_uchar * null_ptr;
1463 zend_uchar bit;
1464 zval *current_field, *end_field, *start_field;
1465
1466 DBG_ENTER("php_mysqlnd_rowp_read_binary_protocol");
1467
1468 if (!fields) {
1470 }
1471
1472 end_field = (start_field = fields) + field_count;
1473
1474 /* skip the first byte, not EODATA_MARKER -> 0x0, status */
1475 p++;
1476 null_ptr= p;
1477 p += (field_count + 9)/8; /* skip null bits */
1478 bit = 4; /* first 2 bits are reserved */
1479
1480 for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) {
1482 const zend_uchar * orig_p = p;
1483
1484 DBG_INF_FMT("Into zval=%p decoding column %u [%s.%s.%s] type=%u field->flags&unsigned=%u flags=%u is_bit=%u",
1485 current_field, i,
1486 fields_metadata[i].db, fields_metadata[i].table, fields_metadata[i].name, fields_metadata[i].type,
1487 fields_metadata[i].flags & UNSIGNED_FLAG, fields_metadata[i].flags, fields_metadata[i].type == MYSQL_TYPE_BIT);
1488 if (*null_ptr & bit) {
1489 DBG_INF("It's null");
1490 ZVAL_NULL(current_field);
1492 } else {
1493 enum_mysqlnd_field_types type = fields_metadata[i].type;
1494 size_t row_position = p - rbp;
1495 if (rbs <= row_position) {
1496 for (j = 0, current_field = start_field; j < i; current_field++, j++) {
1497 zval_ptr_dtor(current_field);
1498 }
1499 php_error_docref(NULL, E_WARNING, "Malformed server packet. No packet space left for the field");
1501 }
1502 mysqlnd_ps_fetch_functions[type].func(current_field, &fields_metadata[i], rbs - row_position, &p);
1503 if (p == NULL) {
1504 for (j = 0, current_field = start_field; j < i; current_field++, j++) {
1505 zval_ptr_dtor(current_field);
1506 }
1508 }
1509
1511 switch (fields_metadata[i].type) {
1513 case MYSQL_TYPE_TINY: statistic = STAT_BINARY_TYPE_FETCHED_INT8; break;
1514 case MYSQL_TYPE_SHORT: statistic = STAT_BINARY_TYPE_FETCHED_INT16; break;
1515 case MYSQL_TYPE_LONG: statistic = STAT_BINARY_TYPE_FETCHED_INT32; break;
1516 case MYSQL_TYPE_FLOAT: statistic = STAT_BINARY_TYPE_FETCHED_FLOAT; break;
1517 case MYSQL_TYPE_DOUBLE: statistic = STAT_BINARY_TYPE_FETCHED_DOUBLE; break;
1518 case MYSQL_TYPE_NULL: statistic = STAT_BINARY_TYPE_FETCHED_NULL; break;
1520 case MYSQL_TYPE_LONGLONG: statistic = STAT_BINARY_TYPE_FETCHED_INT64; break;
1521 case MYSQL_TYPE_INT24: statistic = STAT_BINARY_TYPE_FETCHED_INT24; break;
1522 case MYSQL_TYPE_DATE: statistic = STAT_BINARY_TYPE_FETCHED_DATE; break;
1523 case MYSQL_TYPE_TIME: statistic = STAT_BINARY_TYPE_FETCHED_TIME; break;
1525 case MYSQL_TYPE_YEAR: statistic = STAT_BINARY_TYPE_FETCHED_YEAR; break;
1526 case MYSQL_TYPE_NEWDATE: statistic = STAT_BINARY_TYPE_FETCHED_DATE; break;
1527 case MYSQL_TYPE_VARCHAR: statistic = STAT_BINARY_TYPE_FETCHED_STRING; break;
1528 case MYSQL_TYPE_BIT: statistic = STAT_BINARY_TYPE_FETCHED_BIT; break;
1530 case MYSQL_TYPE_ENUM: statistic = STAT_BINARY_TYPE_FETCHED_ENUM; break;
1531 case MYSQL_TYPE_SET: statistic = STAT_BINARY_TYPE_FETCHED_SET; break;
1532 case MYSQL_TYPE_TINY_BLOB: statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break;
1534 case MYSQL_TYPE_LONG_BLOB: statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break;
1535 case MYSQL_TYPE_BLOB: statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break;
1536 case MYSQL_TYPE_VECTOR: statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break;
1538 case MYSQL_TYPE_STRING: statistic = STAT_BINARY_TYPE_FETCHED_STRING; break;
1540 default: statistic = STAT_BINARY_TYPE_FETCHED_OTHER; break;
1541 }
1542 }
1543 }
1544 MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, statistic, 1,
1546 (Z_TYPE_P(current_field) == IS_STRING)?
1547 Z_STRLEN_P(current_field) : (size_t)(p - orig_p));
1548
1549 if (!((bit<<=1) & 255)) {
1550 bit = 1; /* to the following byte */
1551 null_ptr++;
1552 }
1553 }
1554
1556}
1557/* }}} */
1558
1559
1560/* {{{ php_mysqlnd_rowp_read_text_protocol */
1563 unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
1564 bool as_int_or_float, MYSQLND_STATS * stats)
1565{
1566 unsigned int i, j;
1567 zval *current_field, *end_field, *start_field;
1568 zend_uchar * p = row_buffer->ptr;
1569 const size_t data_size = row_buffer->size;
1570 const zend_uchar * const packet_end = (zend_uchar*) p + data_size;
1571
1572 DBG_ENTER("php_mysqlnd_rowp_read_text_protocol");
1573
1574 if (!fields) {
1576 }
1577
1578 end_field = (start_field = fields) + field_count;
1579
1580 for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) {
1581 /* php_mysqlnd_net_field_length() call should be after *this_field_len_pos = p; */
1583
1584 /* NULL or NOT NULL, this is the question! */
1585 if (len == MYSQLND_NULL_LENGTH) {
1586 ZVAL_NULL(current_field);
1587 } else if (p > packet_end || len > packet_end - p) {
1588 php_error_docref(NULL, E_WARNING, "Malformed server packet. Field length pointing after end of packet");
1589 for (j = 0, current_field = start_field; j < i; current_field++, j++) {
1590 zval_ptr_dtor(current_field);
1591 }
1593 } else {
1594 struct st_mysqlnd_perm_bind perm_bind =
1595 mysqlnd_ps_fetch_functions[fields_metadata[i].type];
1598 switch (fields_metadata[i].type) {
1599 case MYSQL_TYPE_DECIMAL: statistic = STAT_TEXT_TYPE_FETCHED_DECIMAL; break;
1600 case MYSQL_TYPE_TINY: statistic = STAT_TEXT_TYPE_FETCHED_INT8; break;
1601 case MYSQL_TYPE_SHORT: statistic = STAT_TEXT_TYPE_FETCHED_INT16; break;
1602 case MYSQL_TYPE_LONG: statistic = STAT_TEXT_TYPE_FETCHED_INT32; break;
1603 case MYSQL_TYPE_FLOAT: statistic = STAT_TEXT_TYPE_FETCHED_FLOAT; break;
1604 case MYSQL_TYPE_DOUBLE: statistic = STAT_TEXT_TYPE_FETCHED_DOUBLE; break;
1605 case MYSQL_TYPE_NULL: statistic = STAT_TEXT_TYPE_FETCHED_NULL; break;
1607 case MYSQL_TYPE_LONGLONG: statistic = STAT_TEXT_TYPE_FETCHED_INT64; break;
1608 case MYSQL_TYPE_INT24: statistic = STAT_TEXT_TYPE_FETCHED_INT24; break;
1609 case MYSQL_TYPE_DATE: statistic = STAT_TEXT_TYPE_FETCHED_DATE; break;
1610 case MYSQL_TYPE_TIME: statistic = STAT_TEXT_TYPE_FETCHED_TIME; break;
1612 case MYSQL_TYPE_YEAR: statistic = STAT_TEXT_TYPE_FETCHED_YEAR; break;
1613 case MYSQL_TYPE_NEWDATE: statistic = STAT_TEXT_TYPE_FETCHED_DATE; break;
1614 case MYSQL_TYPE_VARCHAR: statistic = STAT_TEXT_TYPE_FETCHED_STRING; break;
1615 case MYSQL_TYPE_BIT: statistic = STAT_TEXT_TYPE_FETCHED_BIT; break;
1617 case MYSQL_TYPE_ENUM: statistic = STAT_TEXT_TYPE_FETCHED_ENUM; break;
1618 case MYSQL_TYPE_SET: statistic = STAT_TEXT_TYPE_FETCHED_SET; break;
1619 case MYSQL_TYPE_JSON: statistic = STAT_TEXT_TYPE_FETCHED_JSON; break;
1620 case MYSQL_TYPE_TINY_BLOB: statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
1622 case MYSQL_TYPE_LONG_BLOB: statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
1623 case MYSQL_TYPE_BLOB: statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
1624 case MYSQL_TYPE_VECTOR: statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
1626 case MYSQL_TYPE_STRING: statistic = STAT_TEXT_TYPE_FETCHED_STRING; break;
1628 default: statistic = STAT_TEXT_TYPE_FETCHED_OTHER; break;
1629 }
1631 }
1632 if (fields_metadata[i].type == MYSQL_TYPE_BIT) {
1633 /*
1634 BIT fields are specially handled. As they come as bit mask, they have
1635 to be converted to human-readable representation.
1636 */
1637 ps_fetch_from_1_to_8_bytes(current_field, &(fields_metadata[i]), 0, (const zend_uchar **) &p, len);
1638 /*
1639 We have advanced in ps_fetch_from_1_to_8_bytes. We should go back because
1640 later in this function there will be an advancement.
1641 */
1642 p -= len;
1643 if (Z_TYPE_P(current_field) == IS_LONG && !as_int_or_float) {
1644 /* we are using the text protocol, so convert to string */
1645 char tmp[22];
1646 const size_t tmp_len = snprintf(tmp, sizeof(tmp), ZEND_ULONG_FMT, Z_LVAL_P(current_field));
1647 ZVAL_STRINGL(current_field, tmp, tmp_len);
1648 } else if (Z_TYPE_P(current_field) == IS_STRING) {
1649 /* nothing to do here, as we want a string and ps_fetch_from_1_to_8_bytes() has given us one */
1650 }
1651 } else if (as_int_or_float && perm_bind.php_type == IS_LONG
1652 && !(fields_metadata[i].flags & ZEROFILL_FLAG)) {
1653 zend_uchar save = *(p + len);
1654 /* We have to make it ASCIIZ temporarily */
1655 *(p + len) = '\0';
1656 if (perm_bind.pack_len < SIZEOF_ZEND_LONG) {
1657 /* direct conversion */
1658 int64_t v =
1659#ifndef PHP_WIN32
1660 atoll((char *) p);
1661#else
1662 _atoi64((char *) p);
1663#endif
1664 ZVAL_LONG(current_field, (zend_long) v); /* the cast is safe */
1665 } else {
1666 uint64_t v =
1667#ifndef PHP_WIN32
1668 strtoull((char *) p, NULL, 10);
1669#else
1670 _strtoui64((char *) p, NULL, 10);
1671#endif
1672 bool uns = fields_metadata[i].flags & UNSIGNED_FLAG? TRUE:FALSE;
1673 /* We have to make it ASCIIZ temporarily */
1674#if SIZEOF_ZEND_LONG==8
1675 if (uns == TRUE && v > 9223372036854775807L)
1676#elif SIZEOF_ZEND_LONG==4
1677 if ((uns == TRUE && v > L64(2147483647)) ||
1678 (uns == FALSE && (( L64(2147483647) < (int64_t) v) ||
1679 (L64(-2147483648) > (int64_t) v))))
1680#else
1681#error Need fix for this architecture
1682#endif /* SIZEOF */
1683 {
1684 ZVAL_STRINGL(current_field, (char *)p, len);
1685 } else {
1686 ZVAL_LONG(current_field, (zend_long) v); /* the cast is safe */
1687 }
1688 }
1689 *(p + len) = save;
1690 } else if (as_int_or_float && perm_bind.php_type == IS_DOUBLE) {
1691 zend_uchar save = *(p + len);
1692 /* We have to make it ASCIIZ temporarily */
1693 *(p + len) = '\0';
1694 ZVAL_DOUBLE(current_field, zend_strtod((char *) p, NULL));
1695 *(p + len) = save;
1696 } else {
1697 ZVAL_STRINGL_FAST(current_field, (char *)p, len);
1698 }
1699 p += len;
1700 }
1701 }
1702
1704}
1705/* }}} */
1706
1707
1708/* {{{ php_mysqlnd_rowp_read */
1709static enum_func_status
1710php_mysqlnd_rowp_read(MYSQLND_CONN_DATA * conn, void * _packet)
1711{
1712 MYSQLND_PACKET_ROW *packet = (MYSQLND_PACKET_ROW *) _packet;
1713 MYSQLND_ERROR_INFO * error_info = &packet->error_info;
1714 MYSQLND_PFC * pfc = conn->protocol_frame_codec;
1715 MYSQLND_VIO * vio = conn->vio;
1716 MYSQLND_STATS * stats = conn->stats;
1717 zend_uchar *p;
1719 size_t data_size = 0;
1720
1721 DBG_ENTER("php_mysqlnd_rowp_read");
1722
1723 ret = php_mysqlnd_read_row_ex(pfc, vio, stats, error_info, &conn->state,
1724 packet->result_set_memory_pool, &packet->row_buffer, &data_size);
1725 if (FAIL == ret) {
1726 goto end;
1727 }
1728 MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, packet_type_to_statistic_byte_count[PROT_ROW_PACKET],
1730 packet_type_to_statistic_packet_count[PROT_ROW_PACKET],
1731 1);
1732
1733 /*
1734 packet->row_buffer->ptr is of size 'data_size'
1735 in pre-7.0 it was really 'data_size + 1' although it was counted as 'data_size'
1736 The +1 was for the additional byte needed to \0 terminate the last string in the row.
1737 This was needed as the zvals of pre-7.0 could use external memory (no copy param to ZVAL_STRINGL).
1738 However, in 7.0+ the strings always copy. Thus this +1 byte was removed. Also the optimization or \0
1739 terminating every string, which did overwrite the lengths from the packet. For this reason we needed
1740 to keep (and copy) the lengths externally.
1741 */
1742 packet->header.size = data_size;
1743 packet->row_buffer.size = data_size;
1744
1745 if (ERROR_MARKER == (*(p = packet->row_buffer.ptr))) {
1746 /*
1747 Error message as part of the result set,
1748 not good but we should not hang. See:
1749 Bug #27876 : SF with cyrillic variable name fails during execution
1750 */
1751 ret = FAIL;
1752 php_mysqlnd_read_error_from_line(p + 1, data_size - 1,
1753 packet->error_info.error,
1754 sizeof(packet->error_info.error),
1755 &packet->error_info.error_no,
1756 packet->error_info.sqlstate
1757 );
1758 } else if (EODATA_MARKER == *p && data_size < 8) { /* EOF */
1759 packet->eof = TRUE;
1760 p++;
1761 if (data_size > 1) {
1762 packet->warning_count = uint2korr(p);
1763 p += 2;
1764 packet->server_status = uint2korr(p);
1765 /* Seems we have 3 bytes reserved for future use */
1766 DBG_INF_FMT("server_status=%u warning_count=%u", packet->server_status, packet->warning_count);
1767 }
1768 } else {
1769 packet->eof = FALSE;
1773 }
1774
1775end:
1776 DBG_RETURN(ret);
1777}
1778/* }}} */
1779
1780
1781/* {{{ php_mysqlnd_stats_read */
1782static enum_func_status
1783php_mysqlnd_stats_read(MYSQLND_CONN_DATA * conn, void * _packet)
1784{
1785 MYSQLND_PACKET_STATS *packet= (MYSQLND_PACKET_STATS *) _packet;
1786 MYSQLND_ERROR_INFO * error_info = conn->error_info;
1787 MYSQLND_PFC * pfc = conn->protocol_frame_codec;
1788 MYSQLND_VIO * vio = conn->vio;
1789 MYSQLND_STATS * stats = conn->stats;
1790 MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
1791 const size_t buf_len = pfc->cmd_buffer.length;
1793
1794 DBG_ENTER("php_mysqlnd_stats_read");
1795
1796 if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "statistics", PROT_STATS_PACKET)) {
1798 }
1799
1800 packet->message.s = mnd_emalloc(packet->header.size + 1);
1801 memcpy(packet->message.s, buf, packet->header.size);
1802 packet->message.s[packet->header.size] = '\0';
1803 packet->message.l = packet->header.size;
1804
1806}
1807/* }}} */
1808
1809
1810/* {{{ php_mysqlnd_stats_free_mem */
1811static
1812void php_mysqlnd_stats_free_mem(void * _packet)
1813{
1815 mysqlnd_set_string(&p->message, NULL, 0);
1816}
1817/* }}} */
1818
1819
1820/* 1 + 4 (id) + 2 (field_c) + 2 (param_c) + 1 (filler) + 2 (warnings ) */
1821#define PREPARE_RESPONSE_SIZE_41 9
1822#define PREPARE_RESPONSE_SIZE_50 12
1823
1824/* {{{ php_mysqlnd_prepare_read */
1825static enum_func_status
1826php_mysqlnd_prepare_read(MYSQLND_CONN_DATA * conn, void * _packet)
1827{
1829 MYSQLND_ERROR_INFO * error_info = conn->error_info;
1830 MYSQLND_PFC * pfc = conn->protocol_frame_codec;
1831 MYSQLND_VIO * vio = conn->vio;
1832 MYSQLND_STATS * stats = conn->stats;
1833 MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
1834 /* In case of an error, we should have place to put it */
1835 const size_t buf_len = pfc->cmd_buffer.length;
1837 zend_uchar *p = buf;
1838 const zend_uchar * const begin = buf;
1839 unsigned int data_size;
1840
1841 DBG_ENTER("php_mysqlnd_prepare_read");
1842
1843 if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "prepare", PROT_PREPARE_RESP_PACKET)) {
1845 }
1847
1848 data_size = packet->header.size;
1849 packet->error_code = uint1korr(p);
1850 p++;
1852
1853 if (ERROR_MARKER == packet->error_code) {
1854 php_mysqlnd_read_error_from_line(p, data_size - 1,
1855 packet->error_info.error,
1856 sizeof(packet->error_info.error),
1857 &packet->error_info.error_no,
1858 packet->error_info.sqlstate
1859 );
1861 }
1862
1863 if (data_size != PREPARE_RESPONSE_SIZE_41 &&
1864 data_size != PREPARE_RESPONSE_SIZE_50 &&
1865 !(data_size > PREPARE_RESPONSE_SIZE_50)) {
1866 DBG_ERR_FMT("Wrong COM_STMT_PREPARE response size. Received %u", data_size);
1867 php_error(E_WARNING, "Wrong COM_STMT_PREPARE response size. Received %u", data_size);
1869 }
1870
1871 packet->stmt_id = uint4korr(p);
1872 p += 4;
1874
1875 /* Number of columns in result set */
1876 packet->field_count = uint2korr(p);
1877 p += 2;
1879
1880 packet->param_count = uint2korr(p);
1881 p += 2;
1883
1884 if (data_size > 9) {
1885 /* 0x0 filler sent by the server for 5.0+ clients */
1886 p++;
1888
1889 packet->warning_count = uint2korr(p);
1890 }
1891
1892 DBG_INF_FMT("Prepare packet read: stmt_id=" ZEND_ULONG_FMT " fields=%u params=%u",
1893 packet->stmt_id, packet->field_count, packet->param_count);
1894
1896
1898premature_end:
1899 DBG_ERR_FMT("PREPARE packet %zu bytes shorter than expected", p - begin - packet->header.size);
1900 php_error_docref(NULL, E_WARNING, "PREPARE packet %zu bytes shorter than expected",
1901 p - begin - packet->header.size);
1903}
1904/* }}} */
1905
1906
1907/* {{{ php_mysqlnd_chg_user_read */
1908static enum_func_status
1909php_mysqlnd_chg_user_read(MYSQLND_CONN_DATA * conn, void * _packet)
1910{
1912 MYSQLND_ERROR_INFO * error_info = conn->error_info;
1913 MYSQLND_PFC * pfc = conn->protocol_frame_codec;
1914 MYSQLND_VIO * vio = conn->vio;
1915 MYSQLND_STATS * stats = conn->stats;
1916 MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
1917 /* There could be an error message */
1918 const size_t buf_len = pfc->cmd_buffer.length;
1920 zend_uchar *p = buf;
1921 const zend_uchar * const begin = buf;
1922
1923 DBG_ENTER("php_mysqlnd_chg_user_read");
1924
1925 if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "change user response", PROT_CHG_USER_RESP_PACKET)) {
1927 }
1929
1930 /*
1931 Don't increment. First byte is ERROR_MARKER on error, but otherwise is starting byte
1932 of encoded sequence for length.
1933 */
1934
1935 /* Should be always 0x0 or ERROR_MARKER for error */
1936 packet->response_code = uint1korr(p);
1937 p++;
1938
1939 if (packet->header.size == 1 && buf[0] == EODATA_MARKER && (packet->server_capabilities & CLIENT_SECURE_CONNECTION)) {
1940 /* We don't handle 3.23 authentication */
1941 packet->server_asked_323_auth = TRUE;
1943 }
1944
1945 if (ERROR_MARKER == packet->response_code) {
1946 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
1947 packet->error_info.error,
1948 sizeof(packet->error_info.error),
1949 &packet->error_info.error_no,
1950 packet->error_info.sqlstate
1951 );
1952 }
1954 if (packet->response_code == 0xFE && packet->header.size > (size_t) (p - buf)) {
1955 packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE);
1956 packet->new_auth_protocol_len = strlen(packet->new_auth_protocol);
1957 p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */
1958 packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf);
1959 if (packet->new_auth_protocol_data_len) {
1960 packet->new_auth_protocol_data = mnd_emalloc(packet->new_auth_protocol_data_len);
1961 memcpy(packet->new_auth_protocol_data, p, packet->new_auth_protocol_data_len);
1962 }
1963 DBG_INF_FMT("The server requested switching auth plugin to : %s", packet->new_auth_protocol);
1964 DBG_INF_FMT("Server salt : [%*s]", (int) packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
1965 }
1966
1968premature_end:
1969 DBG_ERR_FMT("CHANGE_USER packet %zu bytes shorter than expected", p - begin - packet->header.size);
1970 php_error_docref(NULL, E_WARNING, "CHANGE_USER packet %zu bytes shorter than expected",
1971 p - begin - packet->header.size);
1973}
1974/* }}} */
1975
1976
1977/* {{{ php_mysqlnd_chg_user_free_mem */
1978static void
1979php_mysqlnd_chg_user_free_mem(void * _packet)
1980{
1982
1983 if (p->new_auth_protocol) {
1984 mnd_efree(p->new_auth_protocol);
1985 p->new_auth_protocol = NULL;
1986 }
1987 p->new_auth_protocol_len = 0;
1988
1989 if (p->new_auth_protocol_data) {
1990 mnd_efree(p->new_auth_protocol_data);
1991 p->new_auth_protocol_data = NULL;
1992 }
1993 p->new_auth_protocol_data_len = 0;
1994}
1995/* }}} */
1996
1997
1998/* {{{ php_mysqlnd_sha256_pk_request_write */
1999static
2000size_t php_mysqlnd_sha256_pk_request_write(MYSQLND_CONN_DATA * conn, void * _packet)
2001{
2002 MYSQLND_ERROR_INFO * error_info = conn->error_info;
2003 MYSQLND_PFC * pfc = conn->protocol_frame_codec;
2004 MYSQLND_VIO * vio = conn->vio;
2005 MYSQLND_STATS * stats = conn->stats;
2007 size_t sent;
2008
2009 DBG_ENTER("php_mysqlnd_sha256_pk_request_write");
2010
2012 sent = pfc->data->m.send(pfc, vio, buffer, 1, stats, error_info);
2013
2014 DBG_RETURN(sent);
2015}
2016/* }}} */
2017
2018
2019/* {{{ php_mysqlnd_sha256_pk_request_response_read */
2020static enum_func_status
2021php_mysqlnd_sha256_pk_request_response_read(MYSQLND_CONN_DATA * conn, void * _packet)
2022{
2024 MYSQLND_ERROR_INFO * error_info = conn->error_info;
2025 MYSQLND_PFC * pfc = conn->protocol_frame_codec;
2026 MYSQLND_VIO * vio = conn->vio;
2027 MYSQLND_STATS * stats = conn->stats;
2028 MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
2029 const size_t buf_len = pfc->cmd_buffer.length;
2030 zend_uchar * const buf = (zend_uchar *) pfc->cmd_buffer.buffer;
2031 const zend_uchar * p = buf;
2032 const zend_uchar * const begin = buf;
2033
2034 DBG_ENTER("php_mysqlnd_sha256_pk_request_response_read");
2035
2036 /* leave space for terminating safety \0 */
2037 if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "SHA256_PK_REQUEST_RESPONSE", PROT_SHA256_PK_REQUEST_RESPONSE_PACKET)) {
2039 }
2041
2042 p++;
2044
2045 packet->public_key_len = packet->header.size - (p - buf);
2046 packet->public_key = mnd_emalloc(packet->public_key_len + 1);
2047 memcpy(packet->public_key, p, packet->public_key_len);
2048 packet->public_key[packet->public_key_len] = '\0';
2049
2051
2052premature_end:
2053 DBG_ERR_FMT("OK packet %zu bytes shorter than expected", p - begin - packet->header.size);
2054 php_error_docref(NULL, E_WARNING, "SHA256_PK_REQUEST_RESPONSE packet %zu bytes shorter than expected",
2055 p - begin - packet->header.size);
2057}
2058/* }}} */
2059
2060
2061/* {{{ php_mysqlnd_sha256_pk_request_response_free_mem */
2062static void
2063php_mysqlnd_sha256_pk_request_response_free_mem(void * _packet)
2064{
2066 if (p->public_key) {
2067 mnd_efree(p->public_key);
2068 p->public_key = NULL;
2069 }
2070 p->public_key_len = 0;
2071}
2072/* }}} */
2073
2074static
2075size_t php_mysqlnd_cached_sha2_result_write(MYSQLND_CONN_DATA * conn, void * _packet)
2076{
2078 MYSQLND_ERROR_INFO * error_info = conn->error_info;
2079 MYSQLND_PFC * pfc = conn->protocol_frame_codec;
2080 MYSQLND_VIO * vio = conn->vio;
2081 MYSQLND_STATS * stats = conn->stats;
2082 ALLOCA_FLAG(use_heap)
2083 zend_uchar *buffer = do_alloca(MYSQLND_HEADER_SIZE + packet->password_len + 1, use_heap);
2084 size_t sent;
2085
2086 DBG_ENTER("php_mysqlnd_cached_sha2_result_write");
2087
2088 if (packet->request == 1) {
2090 sent = pfc->data->m.send(pfc, vio, buffer, 1, stats, error_info);
2091 } else {
2092 if (packet->password_len != 0) {
2094 }
2095 sent = pfc->data->m.send(pfc, vio, buffer, packet->password_len, stats, error_info);
2096 }
2097
2098 free_alloca(buffer, use_heap);
2099 DBG_RETURN(sent);
2100}
2101
2102static enum_func_status
2103php_mysqlnd_cached_sha2_result_read(MYSQLND_CONN_DATA * conn, void * _packet)
2104{
2106 MYSQLND_ERROR_INFO * error_info = conn->error_info;
2107 MYSQLND_PFC * pfc = conn->protocol_frame_codec;
2108 MYSQLND_VIO * vio = conn->vio;
2109 MYSQLND_STATS * stats = conn->stats;
2110 MYSQLND_CONNECTION_STATE * connection_state = &conn->state;
2111 const size_t buf_len = pfc->cmd_buffer.length;
2112 zend_uchar * const buf = (zend_uchar *) pfc->cmd_buffer.buffer;
2113 const zend_uchar * p = buf;
2114 const zend_uchar * const begin = buf;
2115
2116 DBG_ENTER("php_mysqlnd_cached_sha2_result_read");
2117 if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "PROT_CACHED_SHA2_RESULT_PACKET", PROT_CACHED_SHA2_RESULT_PACKET)) {
2119 }
2121
2122 packet->response_code = uint1korr(p);
2123 p++;
2125
2126 if (ERROR_MARKER == packet->response_code) {
2127 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
2128 packet->error, sizeof(packet->error),
2129 &packet->error_no, packet->sqlstate
2130 );
2132 }
2133 if (0xFE == packet->response_code) {
2134 /* Authentication Switch Response */
2135 if (packet->header.size > (size_t) (p - buf)) {
2136 packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE);
2138 p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */
2139
2140 packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf);
2141 if (packet->new_auth_protocol_data_len) {
2144 }
2145 DBG_INF_FMT("The server requested switching auth plugin to : %s", packet->new_auth_protocol);
2146 DBG_INF_FMT("Server salt : [%zu][%.*s]", packet->new_auth_protocol_data_len, (int) packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
2147 }
2149 }
2150
2151 if (0x1 != packet->response_code) {
2152 DBG_ERR_FMT("Unexpected response code %d", packet->response_code);
2153 }
2154
2155 /* This is not really the response code, but we reuse the field. */
2156 packet->response_code = uint1korr(p);
2157 p++;
2159
2160 packet->result = uint1korr(p);
2162
2164
2165premature_end:
2166 DBG_ERR_FMT("OK packet %zu bytes shorter than expected", p - begin - packet->header.size);
2167 php_error_docref(NULL, E_WARNING, "SHA256_PK_REQUEST_RESPONSE packet %zu bytes shorter than expected",
2168 p - begin - packet->header.size);
2170}
2171
2172/* {{{ packet_methods */
2173static
2174mysqlnd_packet_methods packet_methods[PROT_LAST] =
2175{
2176 {
2177 php_mysqlnd_greet_read,
2178 NULL, /* write */
2179 php_mysqlnd_greet_free_mem,
2180 }, /* PROT_GREET_PACKET */
2181 {
2182 NULL, /* read */
2183 php_mysqlnd_auth_write,
2184 NULL,
2185 }, /* PROT_AUTH_PACKET */
2186 {
2187 php_mysqlnd_auth_response_read, /* read */
2188 NULL, /* write */
2189 php_mysqlnd_auth_response_free_mem,
2190 }, /* PROT_AUTH_RESP_PACKET */
2191 {
2192 NULL, /* read */
2193 php_mysqlnd_change_auth_response_write, /* write */
2194 NULL,
2195 }, /* PROT_CHANGE_AUTH_RESP_PACKET */
2196 {
2197 php_mysqlnd_ok_read, /* read */
2198 NULL, /* write */
2199 php_mysqlnd_ok_free_mem,
2200 }, /* PROT_OK_PACKET */
2201 {
2202 php_mysqlnd_eof_read, /* read */
2203 NULL, /* write */
2204 NULL,
2205 }, /* PROT_EOF_PACKET */
2206 {
2207 NULL, /* read */
2208 php_mysqlnd_cmd_write, /* write */
2209 NULL,
2210 }, /* PROT_CMD_PACKET */
2211 {
2212 php_mysqlnd_rset_header_read, /* read */
2213 NULL, /* write */
2214 php_mysqlnd_rset_header_free_mem,
2215 }, /* PROT_RSET_HEADER_PACKET */
2216 {
2217 php_mysqlnd_rset_field_read, /* read */
2218 NULL, /* write */
2219 NULL,
2220 }, /* PROT_RSET_FLD_PACKET */
2221 {
2222 php_mysqlnd_rowp_read, /* read */
2223 NULL, /* write */
2224 NULL,
2225 }, /* PROT_ROW_PACKET */
2226 {
2227 php_mysqlnd_stats_read, /* read */
2228 NULL, /* write */
2229 php_mysqlnd_stats_free_mem,
2230 }, /* PROT_STATS_PACKET */
2231 {
2232 php_mysqlnd_prepare_read, /* read */
2233 NULL, /* write */
2234 NULL,
2235 }, /* PROT_PREPARE_RESP_PACKET */
2236 {
2237 php_mysqlnd_chg_user_read, /* read */
2238 NULL, /* write */
2239 php_mysqlnd_chg_user_free_mem,
2240 }, /* PROT_CHG_USER_RESP_PACKET */
2241 {
2242 NULL, /* read */
2243 php_mysqlnd_sha256_pk_request_write,
2244 NULL,
2245 }, /* PROT_SHA256_PK_REQUEST_PACKET */
2246 {
2247 php_mysqlnd_sha256_pk_request_response_read,
2248 NULL, /* write */
2249 php_mysqlnd_sha256_pk_request_response_free_mem,
2250 }, /* PROT_SHA256_PK_REQUEST_RESPONSE_PACKET */
2251 {
2252 php_mysqlnd_cached_sha2_result_read,
2253 php_mysqlnd_cached_sha2_result_write,
2254 NULL
2255 } /* PROT_CACHED_SHA2_RESULT_PACKET */
2256};
2257/* }}} */
2258
2259
2260/* {{{ mysqlnd_protocol::init_greet_packet */
2261static void
2262MYSQLND_METHOD(mysqlnd_protocol, init_greet_packet)(struct st_mysqlnd_packet_greet *packet)
2263{
2264 DBG_ENTER("mysqlnd_protocol::init_greet_packet");
2265 memset(packet, 0, sizeof(*packet));
2266 packet->header.m = &packet_methods[PROT_GREET_PACKET];
2268}
2269/* }}} */
2270
2271
2272/* {{{ mysqlnd_protocol::init_auth_packet */
2273static void
2274MYSQLND_METHOD(mysqlnd_protocol, init_auth_packet)(struct st_mysqlnd_packet_auth *packet)
2275{
2276 DBG_ENTER("mysqlnd_protocol::init_auth_packet");
2277 memset(packet, 0, sizeof(*packet));
2278 packet->header.m = &packet_methods[PROT_AUTH_PACKET];
2280}
2281/* }}} */
2282
2283
2284/* {{{ mysqlnd_protocol::init_auth_response_packet */
2285static void
2286MYSQLND_METHOD(mysqlnd_protocol, init_auth_response_packet)(struct st_mysqlnd_packet_auth_response *packet)
2287{
2288 DBG_ENTER("mysqlnd_protocol::init_auth_response_packet");
2289 memset(packet, 0, sizeof(*packet));
2290 packet->header.m = &packet_methods[PROT_AUTH_RESP_PACKET];
2292}
2293/* }}} */
2294
2295
2296/* {{{ mysqlnd_protocol::init_change_auth_response_packet */
2297static void
2298MYSQLND_METHOD(mysqlnd_protocol, init_change_auth_response_packet)(struct st_mysqlnd_packet_change_auth_response *packet)
2299{
2300 DBG_ENTER("mysqlnd_protocol::init_change_auth_response_packet");
2301 memset(packet, 0, sizeof(*packet));
2302 packet->header.m = &packet_methods[PROT_CHANGE_AUTH_RESP_PACKET];
2304}
2305/* }}} */
2306
2307
2308/* {{{ mysqlnd_protocol::init_ok_packet */
2309static void
2310MYSQLND_METHOD(mysqlnd_protocol, init_ok_packet)(struct st_mysqlnd_packet_ok *packet)
2311{
2312 DBG_ENTER("mysqlnd_protocol::init_ok_packet");
2313 memset(packet, 0, sizeof(*packet));
2314 packet->header.m = &packet_methods[PROT_OK_PACKET];
2316}
2317/* }}} */
2318
2319
2320/* {{{ mysqlnd_protocol::init_eof_packet */
2321static void
2322MYSQLND_METHOD(mysqlnd_protocol, init_eof_packet)(struct st_mysqlnd_packet_eof *packet)
2323{
2324 DBG_ENTER("mysqlnd_protocol::init_eof_packet");
2325 memset(packet, 0, sizeof(*packet));
2326 packet->header.m = &packet_methods[PROT_EOF_PACKET];
2328}
2329/* }}} */
2330
2331
2332/* {{{ mysqlnd_protocol::init_command_packet */
2333static void
2334MYSQLND_METHOD(mysqlnd_protocol, init_command_packet)(struct st_mysqlnd_packet_command *packet)
2335{
2336 DBG_ENTER("mysqlnd_protocol::init_command_packet");
2337 memset(packet, 0, sizeof(*packet));
2338 packet->header.m = &packet_methods[PROT_CMD_PACKET];
2340}
2341/* }}} */
2342
2343
2344/* {{{ mysqlnd_protocol::init_rset_packet */
2345static void
2346MYSQLND_METHOD(mysqlnd_protocol, init_rset_header_packet)(struct st_mysqlnd_packet_rset_header *packet)
2347{
2348 DBG_ENTER("mysqlnd_protocol::get_rset_header_packet");
2349 memset(packet, 0, sizeof(*packet));
2350 packet->header.m = &packet_methods[PROT_RSET_HEADER_PACKET];
2352}
2353/* }}} */
2354
2355
2356/* {{{ mysqlnd_protocol::init_result_field_packet */
2357static void
2358MYSQLND_METHOD(mysqlnd_protocol, init_result_field_packet)(struct st_mysqlnd_packet_res_field *packet)
2359{
2360 DBG_ENTER("mysqlnd_protocol::init_result_field_packet");
2361 memset(packet, 0, sizeof(*packet));
2362 packet->header.m = &packet_methods[PROT_RSET_FLD_PACKET];
2364}
2365/* }}} */
2366
2367
2368/* {{{ mysqlnd_protocol::init_row_packet */
2369static void
2370MYSQLND_METHOD(mysqlnd_protocol, init_row_packet)(struct st_mysqlnd_packet_row *packet)
2371{
2372 DBG_ENTER("mysqlnd_protocol::init_row_packet");
2373 memset(packet, 0, sizeof(*packet));
2374 packet->header.m = &packet_methods[PROT_ROW_PACKET];
2376}
2377/* }}} */
2378
2379
2380/* {{{ mysqlnd_protocol::init_stats_packet */
2381static void
2382MYSQLND_METHOD(mysqlnd_protocol, init_stats_packet)(struct st_mysqlnd_packet_stats *packet)
2383{
2384 DBG_ENTER("mysqlnd_protocol::init_stats_packet");
2385 memset(packet, 0, sizeof(*packet));
2386 packet->header.m = &packet_methods[PROT_STATS_PACKET];
2388}
2389/* }}} */
2390
2391
2392/* {{{ mysqlnd_protocol::init_prepare_response_packet */
2393static void
2394MYSQLND_METHOD(mysqlnd_protocol, init_prepare_response_packet)(struct st_mysqlnd_packet_prepare_response *packet)
2395{
2396 DBG_ENTER("mysqlnd_protocol::init_prepare_response_packet");
2397 memset(packet, 0, sizeof(*packet));
2398 packet->header.m = &packet_methods[PROT_PREPARE_RESP_PACKET];
2400}
2401/* }}} */
2402
2403
2404/* {{{ mysqlnd_protocol::init_change_user_response_packet */
2405static void
2406MYSQLND_METHOD(mysqlnd_protocol, init_change_user_response_packet)(struct st_mysqlnd_packet_chg_user_resp *packet)
2407{
2408 DBG_ENTER("mysqlnd_protocol::init_change_user_response_packet");
2409 memset(packet, 0, sizeof(*packet));
2410 packet->header.m = &packet_methods[PROT_CHG_USER_RESP_PACKET];
2412}
2413/* }}} */
2414
2415
2416/* {{{ mysqlnd_protocol::init_sha256_pk_request_packet */
2417static void
2418MYSQLND_METHOD(mysqlnd_protocol, init_sha256_pk_request_packet)(struct st_mysqlnd_packet_sha256_pk_request *packet)
2419{
2420 DBG_ENTER("mysqlnd_protocol::init_sha256_pk_request_packet");
2421 memset(packet, 0, sizeof(*packet));
2422 packet->header.m = &packet_methods[PROT_SHA256_PK_REQUEST_PACKET];
2424}
2425/* }}} */
2426
2427
2428/* {{{ mysqlnd_protocol::init_sha256_pk_request_response_packet */
2429static void
2430MYSQLND_METHOD(mysqlnd_protocol, init_sha256_pk_request_response_packet)(struct st_mysqlnd_packet_sha256_pk_request_response *packet)
2431{
2432 DBG_ENTER("mysqlnd_protocol::init_sha256_pk_request_response_packet");
2433 memset(packet, 0, sizeof(*packet));
2434 packet->header.m = &packet_methods[PROT_SHA256_PK_REQUEST_RESPONSE_PACKET];
2436}
2437/* }}} */
2438
2439/* {{{ mysqlnd_protocol::init_cached_sha2_result_packet */
2440static void
2441MYSQLND_METHOD(mysqlnd_protocol, init_cached_sha2_result_packet)(struct st_mysqlnd_packet_cached_sha2_result *packet)
2442{
2443 DBG_ENTER("mysqlnd_protocol::init_cached_sha2_result_packet");
2444 memset(packet, 0, sizeof(*packet));
2445 packet->header.m = &packet_methods[PROT_CACHED_SHA2_RESULT_PACKET];
2447}
2448/* }}} */
2449
2450
2451/* {{{ mysqlnd_protocol::send_command */
2452static enum_func_status
2453MYSQLND_METHOD(mysqlnd_protocol, send_command)(
2454 MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * payload_decoder_factory,
2455 const enum php_mysqlnd_server_command command,
2456 const zend_uchar * const arg, const size_t arg_len,
2457 const bool silent,
2458
2459 struct st_mysqlnd_connection_state * connection_state,
2460 MYSQLND_ERROR_INFO * error_info,
2461 MYSQLND_UPSERT_STATUS * upsert_status,
2462 MYSQLND_STATS * stats,
2464 void * send_close_ctx)
2465{
2467 MYSQLND_PACKET_COMMAND cmd_packet;
2469 DBG_ENTER("mysqlnd_protocol::send_command");
2470 DBG_INF_FMT("command=%s silent=%u", mysqlnd_command_to_text[command], silent);
2471 DBG_INF_FMT("server_status=%u", UPSERT_STATUS_GET_SERVER_STATUS(upsert_status));
2472 DBG_INF_FMT("sending %zu bytes", arg_len + 1); /* + 1 is for the command */
2473 state = connection_state->m->get(connection_state);
2474
2475 switch (state) {
2476 case CONN_READY:
2477 break;
2478 case CONN_QUIT_SENT:
2480 DBG_ERR("Server is gone");
2482 default:
2484 DBG_ERR_FMT("Command out of sync. State=%u", state);
2486 }
2487
2489 SET_EMPTY_ERROR(error_info);
2490
2491 payload_decoder_factory->m.init_command_packet(&cmd_packet);
2492
2493 cmd_packet.command = command;
2494 if (arg && arg_len) {
2495 cmd_packet.argument.s = (char *) arg;
2496 cmd_packet.argument.l = arg_len;
2497 }
2498
2499 MYSQLND_INC_CONN_STATISTIC(stats, STAT_COM_QUIT + command - 1 /* because of COM_SLEEP */ );
2500
2501 if (! PACKET_WRITE(payload_decoder_factory->conn, &cmd_packet)) {
2502 if (!silent && error_info->error_no != CR_SERVER_GONE_ERROR) {
2503 DBG_ERR_FMT("Error while sending %s packet", mysqlnd_command_to_text[command]);
2504 php_error(E_WARNING, "Error while sending %s packet. PID=%d", mysqlnd_command_to_text[command], getpid());
2505 }
2506 connection_state->m->set(connection_state, CONN_QUIT_SENT);
2507 send_close(send_close_ctx);
2508 DBG_ERR("Server is gone");
2509 ret = FAIL;
2510 }
2511 PACKET_FREE(&cmd_packet);
2512 DBG_RETURN(ret);
2513}
2514/* }}} */
2515
2516
2517/* {{{ mysqlnd_protocol::send_command_handle_OK */
2518static enum_func_status
2519MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_OK)(
2520 MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const payload_decoder_factory,
2521 MYSQLND_ERROR_INFO * const error_info,
2522 MYSQLND_UPSERT_STATUS * const upsert_status,
2523 const bool ignore_upsert_status, /* actually used only by LOAD DATA. COM_QUERY and COM_EXECUTE handle the responses themselves */
2524 MYSQLND_STRING * const last_message)
2525{
2527 MYSQLND_PACKET_OK ok_response;
2528
2529 payload_decoder_factory->m.init_ok_packet(&ok_response);
2530 DBG_ENTER("mysqlnd_protocol::send_command_handle_OK");
2531 if (FAIL == (ret = PACKET_READ(payload_decoder_factory->conn, &ok_response))) {
2532 if (error_info->error_no != CR_SERVER_GONE_ERROR) {
2533 DBG_INF("Error while reading OK packet");
2534 SET_CLIENT_ERROR(error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet");
2535 }
2536 goto end;
2537 }
2538 DBG_INF_FMT("OK from server");
2539 if (0xFF == ok_response.field_count) {
2540 /* The server signalled error. Set the error */
2541 SET_CLIENT_ERROR(error_info, ok_response.error_no, ok_response.sqlstate, ok_response.error);
2542 ret = FAIL;
2543 /*
2544 Cover a protocol design error: error packet does not
2545 contain the server status. Therefore, the client has no way
2546 to find out whether there are more result sets of
2547 a multiple-result-set statement pending. Luckily, in 5.0 an
2548 error always aborts execution of a statement, wherever it is
2549 a multi-statement or a stored procedure, so it should be
2550 safe to unconditionally turn off the flag here.
2551 */
2552 upsert_status->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
2554 } else {
2555 mysqlnd_set_string(last_message, ok_response.message, ok_response.message_len);
2556 if (!ignore_upsert_status) {
2557 UPSERT_STATUS_RESET(upsert_status);
2558 UPSERT_STATUS_SET_WARNINGS(upsert_status, ok_response.warning_count);
2559 UPSERT_STATUS_SET_SERVER_STATUS(upsert_status, ok_response.server_status);
2560 UPSERT_STATUS_SET_AFFECTED_ROWS(upsert_status, ok_response.affected_rows);
2561 UPSERT_STATUS_SET_LAST_INSERT_ID(upsert_status, ok_response.last_insert_id);
2562 } else {
2563 /* LOAD DATA */
2564 }
2565 }
2566end:
2567 PACKET_FREE(&ok_response);
2568 DBG_INF(ret == PASS ? "PASS":"FAIL");
2569 DBG_RETURN(ret);
2570}
2571/* }}} */
2572
2573
2574/* {{{ mysqlnd_protocol::send_command_handle_EOF */
2575static enum_func_status
2576MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_EOF)(
2577 MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const payload_decoder_factory,
2578 MYSQLND_ERROR_INFO * const error_info,
2579 MYSQLND_UPSERT_STATUS * const upsert_status)
2580{
2582 MYSQLND_PACKET_EOF response;
2583
2584 payload_decoder_factory->m.init_eof_packet(&response);
2585
2586 DBG_ENTER("mysqlnd_protocol::send_command_handle_EOF");
2587
2588 if (FAIL == (ret = PACKET_READ(payload_decoder_factory->conn, &response))) {
2589 DBG_INF("Error while reading EOF packet");
2590 SET_CLIENT_ERROR(error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet");
2591 } else if (0xFF == response.field_count) {
2592 /* The server signalled error. Set the error */
2593 DBG_INF_FMT("Error_no=%d SQLstate=%s Error=%s", response.error_no, response.sqlstate, response.error);
2594
2595 SET_CLIENT_ERROR(error_info, response.error_no, response.sqlstate, response.error);
2596
2598 } else if (0xFE != response.field_count) {
2599 SET_CLIENT_ERROR(error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet");
2600 DBG_ERR_FMT("EOF packet expected, field count wasn't 0xFE but 0x%2X", response.field_count);
2601 php_error_docref(NULL, E_WARNING, "EOF packet expected, field count wasn't 0xFE but 0x%2X", response.field_count);
2602 } else {
2603 DBG_INF_FMT("EOF from server");
2604 }
2605 PACKET_FREE(&response);
2606
2607 DBG_INF(ret == PASS ? "PASS":"FAIL");
2608 DBG_RETURN(ret);
2609}
2610/* }}} */
2611
2612
2613/* {{{ send_command_handle_response */
2614static enum_func_status
2615MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_response)(
2616 MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * payload_decoder_factory,
2617 const enum mysqlnd_packet_type ok_packet,
2618 const bool silent,
2619 const enum php_mysqlnd_server_command command,
2620 const bool ignore_upsert_status, /* actually used only by LOAD DATA. COM_QUERY and COM_EXECUTE handle the responses themselves */
2621
2622 MYSQLND_ERROR_INFO * error_info,
2623 MYSQLND_UPSERT_STATUS * upsert_status,
2624 MYSQLND_STRING * last_message
2625 )
2626{
2628
2629 DBG_ENTER("mysqlnd_protocol::send_command_handle_response");
2630 DBG_INF_FMT("silent=%u packet=%u command=%s", silent, ok_packet, mysqlnd_command_to_text[command]);
2631
2632 switch (ok_packet) {
2633 case PROT_OK_PACKET:
2634 ret = payload_decoder_factory->m.send_command_handle_OK(payload_decoder_factory, error_info, upsert_status, ignore_upsert_status, last_message);
2635 break;
2636 case PROT_EOF_PACKET:
2637 ret = payload_decoder_factory->m.send_command_handle_EOF(payload_decoder_factory, error_info, upsert_status);
2638 break;
2639 default:
2640 SET_CLIENT_ERROR(error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet");
2641 php_error_docref(NULL, E_ERROR, "Wrong response packet %u passed to the function", ok_packet);
2642 break;
2643 }
2644 if (!silent && error_info->error_no == CR_MALFORMED_PACKET) {
2645 php_error_docref(NULL, E_WARNING, "Error while reading %s's response packet. PID=%d", mysqlnd_command_to_text[command], getpid());
2646 }
2647 DBG_INF(ret == PASS ? "PASS":"FAIL");
2648 DBG_RETURN(ret);
2649}
2650/* }}} */
2651
2652
2653MYSQLND_CLASS_METHODS_START(mysqlnd_protocol_payload_decoder_factory)
2654 MYSQLND_METHOD(mysqlnd_protocol, init_greet_packet),
2655 MYSQLND_METHOD(mysqlnd_protocol, init_auth_packet),
2656 MYSQLND_METHOD(mysqlnd_protocol, init_auth_response_packet),
2657 MYSQLND_METHOD(mysqlnd_protocol, init_change_auth_response_packet),
2658 MYSQLND_METHOD(mysqlnd_protocol, init_ok_packet),
2659 MYSQLND_METHOD(mysqlnd_protocol, init_command_packet),
2660 MYSQLND_METHOD(mysqlnd_protocol, init_eof_packet),
2661 MYSQLND_METHOD(mysqlnd_protocol, init_rset_header_packet),
2662 MYSQLND_METHOD(mysqlnd_protocol, init_result_field_packet),
2663 MYSQLND_METHOD(mysqlnd_protocol, init_row_packet),
2664 MYSQLND_METHOD(mysqlnd_protocol, init_stats_packet),
2665 MYSQLND_METHOD(mysqlnd_protocol, init_prepare_response_packet),
2666 MYSQLND_METHOD(mysqlnd_protocol, init_change_user_response_packet),
2667 MYSQLND_METHOD(mysqlnd_protocol, init_sha256_pk_request_packet),
2668 MYSQLND_METHOD(mysqlnd_protocol, init_sha256_pk_request_response_packet),
2669 MYSQLND_METHOD(mysqlnd_protocol, init_cached_sha2_result_packet),
2670
2671 MYSQLND_METHOD(mysqlnd_protocol, send_command),
2672 MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_response),
2673 MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_OK),
2674 MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_EOF),
2676
2677
2678/* {{{ mysqlnd_protocol_payload_decoder_factory_init */
2681{
2683 DBG_ENTER("mysqlnd_protocol_payload_decoder_factory_init");
2684 ret = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory).get_protocol_payload_decoder_factory(conn, persistent);
2685 DBG_RETURN(ret);
2686}
2687/* }}} */
2688
2689
2690/* {{{ mysqlnd_protocol_payload_decoder_factory_free */
2691PHPAPI void
2693{
2694 DBG_ENTER("mysqlnd_protocol_payload_decoder_factory_free");
2695
2696 if (factory) {
2697 bool pers = factory->persistent;
2698 mnd_pefree(factory, pers);
2699 }
2701}
2702/* }}} */
size_t len
Definition apprentice.c:174
header(string $header, bool $replace=true, int $response_code=0)
uint32_t v
Definition cdf.c:1237
#define uint4korr(A)
Definition config-win.h:51
#define int4store(T, A)
Definition config-win.h:63
#define int3store(T, A)
Definition config-win.h:60
#define int2store(T, A)
Definition config-win.h:59
#define int8store(T, A)
Definition config-win.h:69
#define uint2korr(A)
Definition config-win.h:49
#define uint3korr(A)
Definition config-win.h:50
#define uint8korr(A)
Definition config-win.h:57
int begin
Definition eaw_table.h:20
error($message)
Definition ext_skel.php:22
zend_ffi_type * type
Definition ffi.c:3812
new_type size
Definition ffi.c:4365
memcpy(ptr1, ptr2, size)
zval * arg
Definition ffi.c:3975
memset(ptr, 0, type->size)
ffi persistent
Definition ffi.c:3633
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
const php_stream_filter_factory * factory
Definition filters.c:1900
#define TRUE
Definition gd_gd.c:7
#define FALSE
Definition gd_gd.c:8
#define NULL
Definition gdcache.h:45
#define PASS(tables)
Definition hash_gost.c:193
again j
PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format,...)
Definition main.c:1173
bool collect_statistics
Definition mysqlnd.h:308
#define MYSQLND_INC_CONN_STATISTIC(conn_stats, statistic)
Definition mysqlnd.h:264
#define MYSQLND_G(v)
#define MYSQLND_METHOD(class, method)
Definition mysqlnd.h:294
#define MYSQLND_INC_CONN_STATISTIC_W_VALUE2(conn_stats, statistic1, value1, statistic2, value2)
Definition mysqlnd.h:272
#define mnd_pestrndup(ptr, size, pers)
#define mnd_pestrdup(ptr, pers)
#define mnd_efree(ptr)
#define mnd_emalloc(size)
#define mnd_pefree(ptr, pers)
PHPAPI const char *const mysqlnd_server_gone
PHPAPI const char *const mysqlnd_out_of_sync
#define SET_CONNECTION_STATE(state_struct, s)
#define UPSERT_STATUS_GET_SERVER_STATUS(status)
#define UPSERT_STATUS_SET_WARNINGS(status, warnings)
#define UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(status)
#define UPSERT_STATUS_SET_LAST_INSERT_ID(status, id)
#define UPSERT_STATUS_RESET(status)
#define UPSERT_STATUS_SET_AFFECTED_ROWS(status, rows)
#define UPSERT_STATUS_SET_SERVER_STATUS(status, server_st)
#define DBG_VOID_RETURN
#define DBG_RETURN(value)
mysqlnd_connection_state
@ CONN_READY
@ CONN_QUIT_SENT
#define ZEROFILL_FLAG
#define UNSIGNED_FLAG
#define CLIENT_SECURE_CONNECTION
#define CR_MALFORMED_PACKET
#define CR_SERVER_GONE_ERROR
#define CLIENT_PLUGIN_AUTH
#define SCRAMBLE_LENGTH_323
@ STAT_TEXT_TYPE_FETCHED_DATETIME
@ STAT_PACKETS_RECEIVED_CHANGE_USER
@ STAT_BYTES_RECEIVED_PURE_DATA_TEXT
@ STAT_PACKETS_RECEIVED_PREPARE_RESPONSE
@ STAT_BINARY_TYPE_FETCHED_DOUBLE
@ STAT_PACKETS_RECEIVED
@ STAT_TEXT_TYPE_FETCHED_INT64
@ STAT_CMD_BUFFER_TOO_SMALL
@ STAT_TEXT_TYPE_FETCHED_JSON
@ STAT_BINARY_TYPE_FETCHED_FLOAT
@ STAT_TEXT_TYPE_FETCHED_INT24
@ STAT_TEXT_TYPE_FETCHED_DATE
@ STAT_PACKETS_RECEIVED_RSET_ROW
@ STAT_BINARY_TYPE_FETCHED_OTHER
@ STAT_TEXT_TYPE_FETCHED_TIMESTAMP
@ STAT_BINARY_TYPE_FETCHED_INT16
@ STAT_BINARY_TYPE_FETCHED_SET
@ STAT_TEXT_TYPE_FETCHED_STRING
@ STAT_BYTES_RECEIVED_CHANGE_USER
@ STAT_PACKETS_RECEIVED_RSET_HEADER
@ STAT_BINARY_TYPE_FETCHED_TIMESTAMP
@ STAT_TEXT_TYPE_FETCHED_DOUBLE
@ STAT_TEXT_TYPE_FETCHED_NULL
@ STAT_BINARY_TYPE_FETCHED_INT64
@ STAT_PACKETS_RECEIVED_EOF
@ STAT_BINARY_TYPE_FETCHED_YEAR
@ STAT_TEXT_TYPE_FETCHED_FLOAT
@ STAT_BINARY_TYPE_FETCHED_DECIMAL
@ STAT_BYTES_RECEIVED_OK
@ STAT_BINARY_TYPE_FETCHED_DATETIME
@ STAT_TEXT_TYPE_FETCHED_GEOMETRY
@ STAT_TEXT_TYPE_FETCHED_YEAR
@ STAT_BYTES_RECEIVED_PREPARE_RESPONSE
@ STAT_PACKETS_RECEIVED_OK
@ STAT_TEXT_TYPE_FETCHED_DECIMAL
@ STAT_TEXT_TYPE_FETCHED_BIT
@ STAT_PACKETS_SENT_CMD
@ STAT_TEXT_TYPE_FETCHED_TIME
@ STAT_TEXT_TYPE_FETCHED_INT8
@ STAT_TEXT_TYPE_FETCHED_INT16
@ STAT_BINARY_TYPE_FETCHED_DATE
@ STAT_BYTES_RECEIVED_RSET_HEADER
@ STAT_BINARY_TYPE_FETCHED_BLOB
@ STAT_ROWS_FETCHED_FROM_SERVER_PS
@ STAT_PROTOCOL_OVERHEAD_IN
@ STAT_BINARY_TYPE_FETCHED_BIT
@ STAT_BINARY_TYPE_FETCHED_TIME
@ STAT_BYTES_RECEIVED_PURE_DATA_PS
@ STAT_BINARY_TYPE_FETCHED_GEOMETRY
@ STAT_PACKETS_RECEIVED_RSET_FIELD_META
@ STAT_TEXT_TYPE_FETCHED_INT32
@ STAT_TEXT_TYPE_FETCHED_ENUM
@ STAT_TEXT_TYPE_FETCHED_OTHER
@ STAT_BYTES_RECEIVED_RSET_FIELD_META
@ STAT_LAST
@ STAT_TEXT_TYPE_FETCHED_BLOB
@ STAT_BINARY_TYPE_FETCHED_NULL
@ STAT_BINARY_TYPE_FETCHED_INT8
@ STAT_BINARY_TYPE_FETCHED_ENUM
@ STAT_BYTES_RECEIVED_RSET_ROW
@ STAT_BINARY_TYPE_FETCHED_INT32
@ STAT_BYTES_RECEIVED_EOF
@ STAT_COM_QUIT
@ STAT_BINARY_TYPE_FETCHED_STRING
@ STAT_ROWS_FETCHED_FROM_SERVER_NORMAL
@ STAT_BINARY_TYPE_FETCHED_INT24
@ STAT_TEXT_TYPE_FETCHED_SET
#define SCRAMBLE_LENGTH
#define CR_UNKNOWN_ERROR
enum mysqlnd_collected_stats enum_mysqlnd_collected_stats
mysqlnd_packet_type
@ PROT_CHANGE_AUTH_RESP_PACKET
@ PROT_SHA256_PK_REQUEST_RESPONSE_PACKET
@ PROT_STATS_PACKET
@ PROT_CACHED_SHA2_RESULT_PACKET
@ PROT_PREPARE_RESP_PACKET
@ PROT_LAST
@ PROT_ROW_PACKET
@ PROT_CHG_USER_RESP_PACKET
@ PROT_AUTH_PACKET
@ PROT_EOF_PACKET
@ PROT_RSET_FLD_PACKET
@ PROT_CMD_PACKET
@ PROT_OK_PACKET
@ PROT_AUTH_RESP_PACKET
@ PROT_SHA256_PK_REQUEST_PACKET
@ PROT_GREET_PACKET
@ PROT_RSET_HEADER_PACKET
#define NUM_FLAG
#define MYSQLND_MAX_PACKET_SIZE
#define MYSQLND_MAX_ALLOWED_USER_LEN
#define CR_COMMANDS_OUT_OF_SYNC
php_mysqlnd_server_command
@ MYSQL_TYPE_VARCHAR
@ MYSQL_TYPE_LONGLONG
@ MYSQL_TYPE_LONG_BLOB
@ MYSQL_TYPE_VAR_STRING
@ MYSQL_TYPE_BLOB
@ MYSQL_TYPE_TINY
@ MYSQL_TYPE_TIME
@ MYSQL_TYPE_SET
@ MYSQL_TYPE_NEWDATE
@ MYSQL_TYPE_VECTOR
@ MYSQL_TYPE_JSON
@ MYSQL_TYPE_STRING
@ MYSQL_TYPE_NULL
@ MYSQL_TYPE_ENUM
@ MYSQL_TYPE_TINY_BLOB
@ MYSQL_TYPE_LONG
@ MYSQL_TYPE_BIT
@ MYSQL_TYPE_GEOMETRY
@ MYSQL_TYPE_NEWDECIMAL
@ MYSQL_TYPE_DECIMAL
@ MYSQL_TYPE_DOUBLE
@ MYSQL_TYPE_MEDIUM_BLOB
@ MYSQL_TYPE_SHORT
@ MYSQL_TYPE_DATE
@ MYSQL_TYPE_FLOAT
@ MYSQL_TYPE_TIMESTAMP
@ MYSQL_TYPE_INT24
@ MYSQL_TYPE_DATETIME
@ MYSQL_TYPE_YEAR
#define MYSQLND_SQLSTATE_LENGTH
#define CR_INVALID_BUFFER_USE
#define SERVER_MORE_RESULTS_EXISTS
#define MYSQLND_MAX_ALLOWED_DB_LEN
enum mysqlnd_field_types enum_mysqlnd_field_types
enum func_status enum_func_status
#define UNKNOWN_SQLSTATE
#define int1store(T, A)
#define atoll
#define uint1korr(A)
void ps_fetch_from_1_to_8_bytes(zval *zv, const MYSQLND_FIELD *const field, const unsigned int pack_len, const zend_uchar **row, unsigned int byte_count)
struct st_mysqlnd_perm_bind mysqlnd_ps_fetch_functions[MYSQL_TYPE_LAST+1]
struct st_mysqlnd_field MYSQLND_FIELD
#define MYSQLND_CLASS_METHODS_END
struct st_mysqlnd_vio MYSQLND_VIO
struct st_mysqlnd_upsert_status MYSQLND_UPSERT_STATUS
struct st_mysqlnd_connection_data MYSQLND_CONN_DATA
struct st_mysqlnd_string MYSQLND_STRING
struct st_mysqlnd_const_string MYSQLND_CSTRING
struct st_mysqlnd_memory_pool MYSQLND_MEMORY_POOL
struct st_mysqlnd_stats MYSQLND_STATS
struct st_mysqlnd_protocol_frame_codec MYSQLND_PFC
struct st_mysqlnd_connection_state MYSQLND_CONNECTION_STATE
struct st_mysqlnd_protocol_payload_decoder_factory MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY
#define SET_EMPTY_ERROR(info)
#define SET_CLIENT_ERROR(info, err_no, sqlstate, error)
struct st_mysqlnd_row_buffer MYSQLND_ROW_BUFFER
enum_func_status(* func_mysqlnd_conn_data__send_close)(MYSQLND_CONN_DATA *conn)
#define MYSQLND_CLASS_METHODS_START(class)
struct st_mysqlnd_error_info MYSQLND_ERROR_INFO
#define MYSQLND_CLASS_METHOD_TABLE_NAME(class)
#define MARIADB_RPL_VERSION_HACK
#define READ_RSET_FIELD(field_name)
enum_func_status php_mysqlnd_rowp_read_text_protocol(MYSQLND_ROW_BUFFER *row_buffer, zval *fields, unsigned int field_count, const MYSQLND_FIELD *fields_metadata, bool as_int_or_float, MYSQLND_STATS *stats)
#define BAIL_IF_NO_MORE_DATA
size_t php_mysqlnd_net_store_length_size(uint64_t length)
PHPAPI void mysqlnd_protocol_payload_decoder_factory_free(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY *const factory)
const char mysqlnd_read_body_name[]
#define PREPARE_RESPONSE_SIZE_50
enum_func_status php_mysqlnd_rowp_read_binary_protocol(MYSQLND_ROW_BUFFER *row_buffer, zval *fields, const unsigned int field_count, const MYSQLND_FIELD *const fields_metadata, const bool as_int_or_float, MYSQLND_STATS *const stats)
const char mysqlnd_read_header_name[]
#define PREPARE_RESPONSE_SIZE_41
PHPAPI MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * mysqlnd_protocol_payload_decoder_factory_init(MYSQLND_CONN_DATA *conn, const bool persistent)
size_t php_mysqlnd_cmd_write(MYSQLND_CONN_DATA *conn, void *_packet)
zend_ulong php_mysqlnd_net_field_length(const zend_uchar **packet)
const char *const mysqlnd_command_to_text[COM_END]
const char *const mysqlnd_empty_string
#define ERROR_MARKER
#define AUTH_WRITE_BUFFER_LEN
zend_uchar * php_mysqlnd_net_store_length(zend_uchar *packet, const uint64_t length)
uint64_t php_mysqlnd_net_field_length_ll(const zend_uchar **packet)
#define EODATA_MARKER
struct st_mysqlnd_packet_prepare_response MYSQLND_PACKET_PREPARE_RESPONSE
struct st_mysqlnd_packet_eof MYSQLND_PACKET_EOF
#define PACKET_FREE(packet)
struct st_mysqlnd_packet_res_field MYSQLND_PACKET_RES_FIELD
struct st_mysqlnd_packet_stats MYSQLND_PACKET_STATS
struct st_mysqlnd_packet_command MYSQLND_PACKET_COMMAND
#define PACKET_WRITE(conn, packet)
struct st_mysqlnd_packet_cached_sha2_result MYSQLND_PACKET_CACHED_SHA2_RESULT
struct st_mysqlnd_packet_header MYSQLND_PACKET_HEADER
#define MYSQLND_HEADER_SIZE
struct st_mysqlnd_packet_ok MYSQLND_PACKET_OK
struct st_mysqlnd_packet_rset_header MYSQLND_PACKET_RSET_HEADER
struct st_mysqlnd_packet_sha256_pk_request_response MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE
struct st_mysqlnd_packet_auth MYSQLND_PACKET_AUTH
struct st_mysqlnd_packet_change_auth_response MYSQLND_PACKET_CHANGE_AUTH_RESPONSE
struct st_mysqlnd_packet_auth_response MYSQLND_PACKET_AUTH_RESPONSE
struct st_mysqlnd_packet_greet MYSQLND_PACKET_GREET
#define MYSQLND_NULL_LENGTH
#define PACKET_READ(conn, packet)
struct st_mysqlnd_packet_row MYSQLND_PACKET_ROW
struct st_mysqlnd_packet_chg_user_resp MYSQLND_PACKET_CHG_USER_RESPONSE
struct st_mysqlnd_packet_methods mysqlnd_packet_methods
#define strlcpy
Definition php.h:159
#define PHPAPI
Definition php.h:71
#define php_error
Definition php.h:310
unsigned const char * end
Definition php_ffi.h:51
#define L64
Definition php_hash.h:30
zend_long error_no
char sqlstate[6]
unsigned char key[REFLECTION_KEY_LEN]
char * msg
Definition phpdbg.h:289
p
Definition session.c:1105
#define FAIL(...)
Definition file.h:177
MYSQLND_ERROR_INFO * error_info
MYSQLND_CONNECTION_STATE state
char sqlstate[MYSQLND_SQLSTATE_LENGTH+1]
char error[MYSQLND_ERRMSG_SIZE+1]
unsigned int db_length
const char * catalog
const char * table
const char * org_table
unsigned int flags
unsigned int org_table_length
unsigned int name_length
unsigned int org_name_length
enum mysqlnd_field_types type
const char * org_name
unsigned int catalog_length
unsigned int decimals
zend_string * sname
unsigned int table_length
const char * name
unsigned int charsetnr
void *(* get_chunk)(MYSQLND_MEMORY_POOL *pool, size_t size)
const zend_uchar * auth_data
char sqlstate[MYSQLND_SQLSTATE_LENGTH+1]
enum php_mysqlnd_server_command command
char error[MYSQLND_ERRMSG_SIZE+1]
char sqlstate[MYSQLND_SQLSTATE_LENGTH+1]
mysqlnd_packet_methods * m
char sqlstate[MYSQLND_SQLSTATE_LENGTH+1]
char error[MYSQLND_ERRMSG_SIZE+1]
MYSQLND_MEMORY_POOL * memory_pool
MYSQLND_PACKET_HEADER header
MYSQLND_ROW_BUFFER row_buffer
MYSQLND_ERROR_INFO error_info
MYSQLND_MEMORY_POOL * result_set_memory_pool
unsigned int php_type
Definition mysqlnd_ps.h:28
struct st_mysqlnd_protocol_frame_codec_data * data
struct st_mysqlnd_vio_data * data
#define ZVAL_STRINGL(z, s, l)
Definition zend_API.h:952
#define ZVAL_STRINGL_FAST(z, s, l)
Definition zend_API.h:983
#define efree(ptr)
Definition zend_alloc.h:155
#define estrdup(s)
Definition zend_alloc.h:164
#define erealloc(ptr, size)
Definition zend_alloc.h:159
#define emalloc(size)
Definition zend_alloc.h:151
struct _zval_struct zval
strlen(string $string)
strncmp(string $string1, string $string2, int $length)
#define snprintf
#define E_ERROR
Definition zend_errors.h:23
#define E_WARNING
Definition zend_errors.h:24
#define ZEND_HASH_FOREACH_END()
Definition zend_hash.h:1086
#define ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(ht, _key, _val)
Definition zend_hash.h:1374
#define ZEND_ULONG_FMT
Definition zend_long.h:88
int32_t zend_long
Definition zend_long.h:42
uint32_t zend_ulong
Definition zend_long.h:43
#define SIZEOF_ZEND_LONG
Definition zend_long.h:50
struct _zend_string zend_string
#define ALLOCA_FLAG(name)
#define MIN(a, b)
#define EXPECTED(condition)
#define do_alloca(p, use_heap)
#define free_alloca(p, use_heap)
#define UNEXPECTED(condition)
ZEND_API zend_string_init_interned_func_t zend_string_init_interned
Definition zend_string.c:31
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_EMPTY_ALLOC()
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
ZEND_API double zend_strtod(const char *s00, const char **se)
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define Z_STRVAL_P(zval_p)
Definition zend_types.h:975
#define ZVAL_NULL(z)
#define ZVAL_LONG(z, l)
#define IS_STRING
Definition zend_types.h:606
#define IS_DOUBLE
Definition zend_types.h:605
#define Z_STRLEN_P(zval_p)
Definition zend_types.h:978
#define IS_LONG
Definition zend_types.h:604
#define ZVAL_DOUBLE(z, d)
unsigned char zend_uchar
Definition zend_types.h:57
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
zend_string * name
zval * ret