PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/mysqlnd - mysqlnd_wireprotocol.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 1091 1440 75.8 %
Date: 2016-06-25 Functions: 53 63 84.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   +----------------------------------------------------------------------+
       3             :   | PHP Version 7                                                        |
       4             :   +----------------------------------------------------------------------+
       5             :   | Copyright (c) 2006-2016 The PHP Group                                |
       6             :   +----------------------------------------------------------------------+
       7             :   | This source file is subject to version 3.01 of the PHP license,      |
       8             :   | that is bundled with this package in the file LICENSE, and is        |
       9             :   | available through the world-wide-web at the following url:           |
      10             :   | http://www.php.net/license/3_01.txt                                  |
      11             :   | If you did not receive a copy of the PHP license and are unable to   |
      12             :   | obtain it through the world-wide-web, please send a note to          |
      13             :   | license@php.net so we can mail you a copy immediately.               |
      14             :   +----------------------------------------------------------------------+
      15             :   | Authors: Andrey Hristov <andrey@mysql.com>                           |
      16             :   |          Ulf Wendel <uwendel@mysql.com>                              |
      17             :   |          Georg Richter <georg@mysql.com>                             |
      18             :   +----------------------------------------------------------------------+
      19             : */
      20             : #include "php.h"
      21             : #include "mysqlnd.h"
      22             : #include "mysqlnd_connection.h"
      23             : #include "mysqlnd_ps.h"
      24             : #include "mysqlnd_priv.h"
      25             : #include "mysqlnd_wireprotocol.h"
      26             : #include "mysqlnd_statistics.h"
      27             : #include "mysqlnd_debug.h"
      28             : 
      29             : #define BAIL_IF_NO_MORE_DATA \
      30             :         if ((size_t)(p - begin) > packet->header.size) { \
      31             :                 php_error_docref(NULL, E_WARNING, "Premature end of data (mysqlnd_wireprotocol.c:%u)", __LINE__); \
      32             :                 goto premature_end; \
      33             :         } \
      34             : 
      35             : 
      36             : static const char *unknown_sqlstate= "HY000";
      37             : const char * const mysqlnd_empty_string = "";
      38             : 
      39             : /* Used in mysqlnd_debug.c */
      40             : const char mysqlnd_read_header_name[]   = "mysqlnd_read_header";
      41             : const char mysqlnd_read_body_name[]             = "mysqlnd_read_body";
      42             : 
      43             : #define ERROR_MARKER 0xFF
      44             : #define EODATA_MARKER 0xFE
      45             : 
      46             : /* {{{ mysqlnd_command_to_text
      47             :  */
      48             : const char * const mysqlnd_command_to_text[COM_END] =
      49             : {
      50             :   "SLEEP", "QUIT", "INIT_DB", "QUERY", "FIELD_LIST",
      51             :   "CREATE_DB", "DROP_DB", "REFRESH", "SHUTDOWN", "STATISTICS",
      52             :   "PROCESS_INFO", "CONNECT", "PROCESS_KILL", "DEBUG", "PING",
      53             :   "TIME", "DELAYED_INSERT", "CHANGE_USER", "BINLOG_DUMP",
      54             :   "TABLE_DUMP", "CONNECT_OUT", "REGISTER_SLAVE",
      55             :   "STMT_PREPARE", "STMT_EXECUTE", "STMT_SEND_LONG_DATA", "STMT_CLOSE",
      56             :   "STMT_RESET", "SET_OPTION", "STMT_FETCH", "DAEMON", "BINLOG_DUMP_GTID",
      57             :   "RESET_CONNECTION"
      58             : };
      59             : /* }}} */
      60             : 
      61             : 
      62             : 
      63             : static enum_mysqlnd_collected_stats packet_type_to_statistic_byte_count[PROT_LAST] =
      64             : {
      65             :         STAT_LAST,
      66             :         STAT_LAST,
      67             :         STAT_BYTES_RECEIVED_OK,
      68             :         STAT_BYTES_RECEIVED_EOF,
      69             :         STAT_LAST,
      70             :         STAT_BYTES_RECEIVED_RSET_HEADER,
      71             :         STAT_BYTES_RECEIVED_RSET_FIELD_META,
      72             :         STAT_BYTES_RECEIVED_RSET_ROW,
      73             :         STAT_BYTES_RECEIVED_PREPARE_RESPONSE,
      74             :         STAT_BYTES_RECEIVED_CHANGE_USER,
      75             : };
      76             : 
      77             : static enum_mysqlnd_collected_stats packet_type_to_statistic_packet_count[PROT_LAST] =
      78             : {
      79             :         STAT_LAST,
      80             :         STAT_LAST,
      81             :         STAT_PACKETS_RECEIVED_OK,
      82             :         STAT_PACKETS_RECEIVED_EOF,
      83             :         STAT_LAST,
      84             :         STAT_PACKETS_RECEIVED_RSET_HEADER,
      85             :         STAT_PACKETS_RECEIVED_RSET_FIELD_META,
      86             :         STAT_PACKETS_RECEIVED_RSET_ROW,
      87             :         STAT_PACKETS_RECEIVED_PREPARE_RESPONSE,
      88             :         STAT_PACKETS_RECEIVED_CHANGE_USER,
      89             : };
      90             : 
      91             : 
      92             : /* {{{ php_mysqlnd_net_field_length
      93             :    Get next field's length */
      94             : zend_ulong
      95      320557 : php_mysqlnd_net_field_length(const zend_uchar **packet)
      96             : {
      97      320557 :         register const zend_uchar *p= (const zend_uchar *)*packet;
      98             : 
      99      320557 :         if (*p < 251) {
     100      287529 :                 (*packet)++;
     101      287529 :                 return (zend_ulong) *p;
     102             :         }
     103             : 
     104       33028 :         switch (*p) {
     105             :                 case 251:
     106         703 :                         (*packet)++;
     107         703 :                         return MYSQLND_NULL_LENGTH;
     108             :                 case 252:
     109       32306 :                         (*packet) += 3;
     110       32306 :                         return (zend_ulong) uint2korr(p+1);
     111             :                 case 253:
     112          18 :                         (*packet) += 4;
     113          18 :                         return (zend_ulong) uint3korr(p+1);
     114             :                 default:
     115           1 :                         (*packet) += 9;
     116           1 :                         return (zend_ulong) uint4korr(p+1);
     117             :         }
     118             : }
     119             : /* }}} */
     120             : 
     121             : 
     122             : /* {{{ php_mysqlnd_net_field_length_ll
     123             :    Get next field's length */
     124             : uint64_t
     125       46708 : php_mysqlnd_net_field_length_ll(const zend_uchar **packet)
     126             : {
     127       46708 :         register const zend_uchar *p = (zend_uchar *)*packet;
     128             : 
     129       46708 :         if (*p < 251) {
     130       46698 :                 (*packet)++;
     131       46698 :                 return (uint64_t) *p;
     132             :         }
     133             : 
     134          10 :         switch (*p) {
     135             :                 case 251:
     136           0 :                         (*packet)++;
     137           0 :                         return (uint64_t) MYSQLND_NULL_LENGTH;
     138             :                 case 252:
     139           8 :                         (*packet) += 3;
     140           8 :                         return (uint64_t) uint2korr(p + 1);
     141             :                 case 253:
     142           0 :                         (*packet) += 4;
     143           0 :                         return (uint64_t) uint3korr(p + 1);
     144             :                 default:
     145           2 :                         (*packet) += 9;
     146           2 :                         return (uint64_t) uint8korr(p + 1);
     147             :         }
     148             : }
     149             : /* }}} */
     150             : 
     151             : 
     152             : /* {{{ php_mysqlnd_net_store_length */
     153             : zend_uchar *
     154         658 : php_mysqlnd_net_store_length(zend_uchar *packet, const uint64_t length)
     155             : {
     156         658 :         if (length < (uint64_t) L64(251)) {
     157         581 :                 *packet = (zend_uchar) length;
     158         581 :                 return packet + 1;
     159             :         }
     160             : 
     161          77 :         if (length < (uint64_t) L64(65536)) {
     162          73 :                 *packet++ = 252;
     163          73 :                 int2store(packet,(unsigned int) length);
     164          73 :                 return packet + 2;
     165             :         }
     166             : 
     167           4 :         if (length < (uint64_t) L64(16777216)) {
     168           4 :                 *packet++ = 253;
     169           4 :                 int3store(packet,(zend_ulong) length);
     170           4 :                 return packet + 3;
     171             :         }
     172           0 :         *packet++ = 254;
     173           0 :         int8store(packet, length);
     174           0 :         return packet + 8;
     175             : }
     176             : /* }}} */
     177             : 
     178             : 
     179             : /* {{{ php_mysqlnd_net_store_length_size */
     180             : size_t
     181           0 : php_mysqlnd_net_store_length_size(uint64_t length)
     182             : {
     183           0 :         if (length < (uint64_t) L64(251)) {
     184           0 :                 return 1;
     185             :         }
     186           0 :         if (length < (uint64_t) L64(65536)) {
     187           0 :                 return 3;
     188             :         }
     189           0 :         if (length < (uint64_t) L64(16777216)) {
     190           0 :                 return 4;
     191             :         }
     192           0 :         return 9;
     193             : }
     194             : /* }}} */
     195             : 
     196             : 
     197             : /* {{{ php_mysqlnd_read_error_from_line */
     198             : static enum_func_status
     199         874 : php_mysqlnd_read_error_from_line(const zend_uchar * const buf, const size_t buf_len,
     200             :                                                                  char *error, const size_t error_buf_len,
     201             :                                                                  unsigned int *error_no, char *sqlstate)
     202             : {
     203         874 :         const zend_uchar *p = buf;
     204         874 :         size_t error_msg_len = 0;
     205             : 
     206         874 :         DBG_ENTER("php_mysqlnd_read_error_from_line");
     207             : 
     208         874 :         *error_no = CR_UNKNOWN_ERROR;
     209         874 :         memcpy(sqlstate, unknown_sqlstate, MYSQLND_SQLSTATE_LENGTH);
     210             : 
     211         874 :         if (buf_len > 2) {
     212         874 :                 *error_no = uint2korr(p);
     213         874 :                 p+= 2;
     214             :                 /*
     215             :                   sqlstate is following. No need to check for buf_left_len as we checked > 2 above,
     216             :                   if it was >=2 then we would need a check
     217             :                 */
     218         874 :                 if (*p == '#') {
     219         874 :                         ++p;
     220         874 :                         if ((buf_len - (p - buf)) >= MYSQLND_SQLSTATE_LENGTH) {
     221         874 :                                 memcpy(sqlstate, p, MYSQLND_SQLSTATE_LENGTH);
     222         874 :                                 p+= MYSQLND_SQLSTATE_LENGTH;
     223             :                         } else {
     224           0 :                                 goto end;
     225             :                         }
     226             :                 }
     227         874 :                 if ((buf_len - (p - buf)) > 0) {
     228         874 :                         error_msg_len = MIN((int)((buf_len - (p - buf))), (int) (error_buf_len - 1));
     229         874 :                         memcpy(error, p, error_msg_len);
     230             :                 }
     231             :         }
     232             : end:
     233         874 :         sqlstate[MYSQLND_SQLSTATE_LENGTH] = '\0';
     234         874 :         error[error_msg_len]= '\0';
     235             : 
     236         874 :         DBG_RETURN(FAIL);
     237             : }
     238             : /* }}} */
     239             : 
     240             : 
     241             : /* {{{ mysqlnd_read_header */
     242             : static enum_func_status
     243      291613 : mysqlnd_read_header(MYSQLND_PFC * pfc, MYSQLND_VIO * vio, MYSQLND_PACKET_HEADER * header,
     244             :                                         MYSQLND_STATS * conn_stats, MYSQLND_ERROR_INFO * error_info)
     245             : {
     246             :         zend_uchar buffer[MYSQLND_HEADER_SIZE];
     247             : 
     248      291613 :         DBG_ENTER(mysqlnd_read_header_name);
     249      291613 :         DBG_INF_FMT("compressed=%u", pfc->data->compressed);
     250      291613 :         if (FAIL == pfc->data->m.receive(pfc, vio, buffer, MYSQLND_HEADER_SIZE, conn_stats, error_info)) {
     251           3 :                 DBG_RETURN(FAIL);
     252             :         }
     253             : 
     254      291610 :         header->size = uint3korr(buffer);
     255      291610 :         header->packet_no = uint1korr(buffer + 3);
     256             : 
     257      291610 :         DBG_INF_FMT("HEADER: prot_packet_no=%u size=%3u", header->packet_no, header->size);
     258      291610 :         MYSQLND_INC_CONN_STATISTIC_W_VALUE2(conn_stats,
     259             :                                                         STAT_PROTOCOL_OVERHEAD_IN, MYSQLND_HEADER_SIZE,
     260             :                                                         STAT_PACKETS_RECEIVED, 1);
     261             : 
     262      291610 :         if (pfc->data->compressed || pfc->data->packet_no == header->packet_no) {
     263             :                 /*
     264             :                   Have to increase the number, so we can send correct number back. It will
     265             :                   round at 255 as this is unsigned char. The server needs this for simple
     266             :                   flow control checking.
     267             :                 */
     268      291609 :                 pfc->data->packet_no++;
     269      291609 :                 DBG_RETURN(PASS);
     270             :         }
     271             : 
     272           3 :         DBG_ERR_FMT("Logical link: packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
     273           2 :                                 pfc->data->packet_no, header->packet_no, header->size);
     274             : 
     275           3 :         php_error(E_WARNING, "Packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
     276           2 :                           pfc->data->packet_no, header->packet_no, header->size);
     277           1 :         DBG_RETURN(FAIL);
     278             : }
     279             : /* }}} */
     280             : 
     281             : 
     282             : /* {{{ mysqlnd_read_packet_header_and_body */
     283             : static enum_func_status
     284      200097 : mysqlnd_read_packet_header_and_body(MYSQLND_PACKET_HEADER * packet_header,
     285             :                                                                         MYSQLND_PFC * pfc,
     286             :                                                                         MYSQLND_VIO * vio,
     287             :                                                                         MYSQLND_STATS * stats,
     288             :                                                                         MYSQLND_ERROR_INFO * error_info,
     289             :                                                                         MYSQLND_CONNECTION_STATE * connection_state,
     290             :                                                                         zend_uchar * buf, size_t buf_size, const char * const packet_type_as_text,
     291             :                                                                         enum mysqlnd_packet_type packet_type)
     292             : {
     293      200097 :         DBG_ENTER("mysqlnd_read_packet_header_and_body");
     294      200097 :         DBG_INF_FMT("buf=%p size=%u", buf, buf_size);
     295      200097 :         if (FAIL == mysqlnd_read_header(pfc, vio, packet_header, stats, error_info)) {
     296           2 :                 SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
     297           2 :                 SET_CLIENT_ERROR(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
     298           2 :                 php_error_docref(NULL, E_WARNING, "%s", mysqlnd_server_gone);
     299           2 :                 DBG_ERR_FMT("Can't read %s's header", packet_type_as_text);
     300           2 :                 DBG_RETURN(FAIL);
     301             :         }
     302      200095 :         if (buf_size < packet_header->size) {
     303           0 :                 DBG_ERR_FMT("Packet buffer %u wasn't big enough %u, %u bytes will be unread",
     304             :                                         buf_size, packet_header->size, packet_header->size - buf_size);
     305           0 :                 DBG_RETURN(FAIL);
     306             :         }
     307      200095 :         if (FAIL == pfc->data->m.receive(pfc, vio, buf, packet_header->size, stats, error_info)) {
     308           0 :                 SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
     309           0 :                 SET_CLIENT_ERROR(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
     310           0 :                 php_error_docref(NULL, E_WARNING, "%s", mysqlnd_server_gone);
     311           0 :                 DBG_ERR_FMT("Empty '%s' packet body", packet_type_as_text);
     312           0 :                 DBG_RETURN(FAIL);
     313             :         }
     314      200095 :         MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, packet_type_to_statistic_byte_count[packet_type],
     315             :                                                                                 MYSQLND_HEADER_SIZE + packet_header->size,
     316             :                                                                                 packet_type_to_statistic_packet_count[packet_type],
     317             :                                                                                 1);
     318      200095 :         DBG_RETURN(PASS);
     319             : }
     320             : /* }}} */
     321             : 
     322             : 
     323             : /* {{{ php_mysqlnd_greet_read */
     324             : static enum_func_status
     325        1692 : php_mysqlnd_greet_read(void * _packet)
     326             : {
     327             :         zend_uchar buf[2048];
     328        1692 :         const zend_uchar * p = buf;
     329        1692 :         const zend_uchar * const begin = buf;
     330        1692 :         const zend_uchar * pad_start = NULL;
     331        1692 :         MYSQLND_PACKET_GREET *packet= (MYSQLND_PACKET_GREET *) _packet;
     332        1692 :         MYSQLND_ERROR_INFO * error_info = packet->header.error_info;
     333        1692 :         MYSQLND_PFC * pfc = packet->header.protocol_frame_codec;
     334        1692 :         MYSQLND_VIO * vio = packet->header.vio;
     335        1692 :         MYSQLND_STATS * stats = packet->header.stats;
     336        1692 :         MYSQLND_CONNECTION_STATE * connection_state = packet->header.connection_state;
     337             : 
     338        1692 :         DBG_ENTER("php_mysqlnd_greet_read");
     339             : 
     340        1692 :         if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, sizeof(buf), "greeting", PROT_GREET_PACKET)) {
     341           0 :                 DBG_RETURN(FAIL);
     342             :         }
     343        1692 :         BAIL_IF_NO_MORE_DATA;
     344             : 
     345        1692 :         packet->authentication_plugin_data.s = packet->intern_auth_plugin_data;
     346        1692 :         packet->authentication_plugin_data.l = sizeof(packet->intern_auth_plugin_data);
     347             : 
     348        1692 :         if (packet->header.size < sizeof(buf)) {
     349             :                 /*
     350             :                   Null-terminate the string, so strdup can work even if the packets have a string at the end,
     351             :                   which is not ASCIIZ
     352             :                 */
     353        1692 :                 buf[packet->header.size] = '\0';
     354             :         }
     355             : 
     356        1692 :         packet->protocol_version = uint1korr(p);
     357        1692 :         p++;
     358        1692 :         BAIL_IF_NO_MORE_DATA;
     359             : 
     360        1692 :         if (ERROR_MARKER == packet->protocol_version) {
     361           0 :                 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
     362             :                                                                                  packet->error, sizeof(packet->error),
     363             :                                                                                  &packet->error_no, packet->sqlstate
     364             :                                                                                 );
     365             :                 /*
     366             :                   The server doesn't send sqlstate in the greet packet.
     367             :                   It's a bug#26426 , so we have to set it correctly ourselves.
     368             :                   It's probably "Too many connections, which has SQL state 08004".
     369             :                 */
     370           0 :                 if (packet->error_no == 1040) {
     371           0 :                         memcpy(packet->sqlstate, "08004", MYSQLND_SQLSTATE_LENGTH);
     372             :                 }
     373           0 :                 DBG_RETURN(PASS);
     374             :         }
     375             : 
     376        1692 :         packet->server_version = estrdup((char *)p);
     377        1692 :         p+= strlen(packet->server_version) + 1; /* eat the '\0' */
     378        1692 :         BAIL_IF_NO_MORE_DATA;
     379             : 
     380        1692 :         packet->thread_id = uint4korr(p);
     381        1692 :         p+=4;
     382        1692 :         BAIL_IF_NO_MORE_DATA;
     383             : 
     384        1692 :         memcpy(packet->authentication_plugin_data.s, p, SCRAMBLE_LENGTH_323);
     385        1692 :         p+= SCRAMBLE_LENGTH_323;
     386        1692 :         BAIL_IF_NO_MORE_DATA;
     387             : 
     388             :         /* pad1 */
     389        1692 :         p++;
     390        1692 :         BAIL_IF_NO_MORE_DATA;
     391             : 
     392        1692 :         packet->server_capabilities = uint2korr(p);
     393        1692 :         p+= 2;
     394        1692 :         BAIL_IF_NO_MORE_DATA;
     395             : 
     396        1692 :         packet->charset_no = uint1korr(p);
     397        1692 :         p++;
     398        1692 :         BAIL_IF_NO_MORE_DATA;
     399             : 
     400        1692 :         packet->server_status = uint2korr(p);
     401        1692 :         p+= 2;
     402        1692 :         BAIL_IF_NO_MORE_DATA;
     403             : 
     404             :         /* pad2 */
     405        1692 :         pad_start = p;
     406        1692 :         p+= 13;
     407        1692 :         BAIL_IF_NO_MORE_DATA;
     408             : 
     409        1692 :         if ((size_t) (p - buf) < packet->header.size) {
     410             :                 /* auth_plugin_data is split into two parts */
     411        1692 :                 memcpy(packet->authentication_plugin_data.s + SCRAMBLE_LENGTH_323, p, SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
     412        1692 :                 p+= SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323;
     413        1692 :                 p++; /* 0x0 at the end of the scramble and thus last byte in the packet in 5.1 and previous */
     414             :         } else {
     415           0 :                 packet->pre41 = TRUE;
     416             :         }
     417             : 
     418             :         /* Is this a 5.5+ server ? */
     419        1692 :         if ((size_t) (p - buf) < packet->header.size) {
     420             :                  /* backtrack one byte, the 0x0 at the end of the scramble in 5.1 and previous */
     421           0 :                 p--;
     422             : 
     423             :         /* Additional 16 bits for server capabilities */
     424           0 :                 packet->server_capabilities |= uint2korr(pad_start) << 16;
     425             :                 /* And a length of the server scramble in one byte */
     426           0 :                 packet->authentication_plugin_data.l = uint1korr(pad_start + 2);
     427           0 :                 if (packet->authentication_plugin_data.l > SCRAMBLE_LENGTH) {
     428             :                         /* more data*/
     429           0 :                         char * new_auth_plugin_data = emalloc(packet->authentication_plugin_data.l);
     430           0 :                         if (!new_auth_plugin_data) {
     431           0 :                                 goto premature_end;
     432             :                         }
     433             :                         /* copy what we already have */
     434           0 :                         memcpy(new_auth_plugin_data, packet->authentication_plugin_data.s, SCRAMBLE_LENGTH);
     435             :                         /* add additional scramble data 5.5+ sent us */
     436           0 :                         memcpy(new_auth_plugin_data + SCRAMBLE_LENGTH, p, packet->authentication_plugin_data.l - SCRAMBLE_LENGTH);
     437           0 :                         p+= (packet->authentication_plugin_data.l - SCRAMBLE_LENGTH);
     438           0 :                         packet->authentication_plugin_data.s = new_auth_plugin_data;
     439             :                 }
     440             :         }
     441             : 
     442        1692 :         if (packet->server_capabilities & CLIENT_PLUGIN_AUTH) {
     443           0 :                 BAIL_IF_NO_MORE_DATA;
     444             :                 /* The server is 5.5.x and supports authentication plugins */
     445           0 :                 packet->auth_protocol = estrdup((char *)p);
     446           0 :                 p+= strlen(packet->auth_protocol) + 1; /* eat the '\0' */
     447             :         }
     448             : 
     449        3384 :         DBG_INF_FMT("proto=%u server=%s thread_id=%u",
     450        1692 :                                 packet->protocol_version, packet->server_version, packet->thread_id);
     451             : 
     452        6768 :         DBG_INF_FMT("server_capabilities=%u charset_no=%u server_status=%i auth_protocol=%s scramble_length=%u",
     453        3384 :                                 packet->server_capabilities, packet->charset_no, packet->server_status,
     454        1692 :                                 packet->auth_protocol? packet->auth_protocol:"n/a", packet->authentication_plugin_data.l);
     455             : 
     456        1692 :         DBG_RETURN(PASS);
     457             : premature_end:
     458           0 :         DBG_ERR_FMT("GREET packet %d bytes shorter than expected", p - begin - packet->header.size);
     459           0 :         php_error_docref(NULL, E_WARNING, "GREET packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
     460           0 :                                          p - begin - packet->header.size);
     461           0 :         DBG_RETURN(FAIL);
     462             : }
     463             : /* }}} */
     464             : 
     465             : 
     466             : /* {{{ php_mysqlnd_greet_free_mem */
     467             : static
     468        1692 : void php_mysqlnd_greet_free_mem(void * _packet, zend_bool stack_allocation)
     469             : {
     470        1692 :         MYSQLND_PACKET_GREET *p= (MYSQLND_PACKET_GREET *) _packet;
     471        1692 :         if (p->server_version) {
     472        1692 :                 efree(p->server_version);
     473        1692 :                 p->server_version = NULL;
     474             :         }
     475        1692 :         if (p->authentication_plugin_data.s && p->authentication_plugin_data.s != p->intern_auth_plugin_data) {
     476           0 :                 efree(p->authentication_plugin_data.s);
     477           0 :                 p->authentication_plugin_data.s = NULL;
     478             :         }
     479        1692 :         if (p->auth_protocol) {
     480           0 :                 efree(p->auth_protocol);
     481           0 :                 p->auth_protocol = NULL;
     482             :         }
     483        1692 :         if (!stack_allocation) {
     484        1692 :                 mnd_pefree(p, p->header.persistent);
     485             :         }
     486        1692 : }
     487             : /* }}} */
     488             : 
     489             : 
     490             : #define AUTH_WRITE_BUFFER_LEN (MYSQLND_HEADER_SIZE + MYSQLND_MAX_ALLOWED_USER_LEN + SCRAMBLE_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1 + 4096)
     491             : 
     492             : /* {{{ php_mysqlnd_auth_write */
     493             : static
     494        1767 : size_t php_mysqlnd_auth_write(void * _packet)
     495             : {
     496             :         zend_uchar buffer[AUTH_WRITE_BUFFER_LEN];
     497        1767 :         zend_uchar *p = buffer + MYSQLND_HEADER_SIZE; /* start after the header */
     498             :         size_t len;
     499        1767 :         MYSQLND_PACKET_AUTH * packet= (MYSQLND_PACKET_AUTH *) _packet;
     500        1767 :         MYSQLND_CONN_DATA * conn = packet->header.conn;
     501        1767 :         MYSQLND_ERROR_INFO * error_info = packet->header.error_info;
     502        1767 :         MYSQLND_PFC * pfc = packet->header.protocol_frame_codec;
     503        1767 :         MYSQLND_VIO * vio = packet->header.vio;
     504        1767 :         MYSQLND_STATS * stats = packet->header.stats;
     505        1767 :         MYSQLND_CONNECTION_STATE * connection_state = packet->header.connection_state;
     506             : 
     507        1767 :         DBG_ENTER("php_mysqlnd_auth_write");
     508             : 
     509        1767 :         if (!packet->is_change_user_packet) {
     510        1692 :                 int4store(p, packet->client_flags);
     511        1692 :                 p+= 4;
     512             : 
     513        1692 :                 int4store(p, packet->max_packet_size);
     514        1692 :                 p+= 4;
     515             : 
     516        1692 :                 int1store(p, packet->charset_no);
     517        1692 :                 p++;
     518             : 
     519        1692 :                 memset(p, 0, 23); /* filler */
     520        1692 :                 p+= 23;
     521             :         }
     522             : 
     523        1767 :         if (packet->send_auth_data || packet->is_change_user_packet) {
     524        1763 :                 len = MIN(strlen(packet->user), MYSQLND_MAX_ALLOWED_USER_LEN);
     525        1763 :                 memcpy(p, packet->user, len);
     526        1763 :                 p+= len;
     527        1763 :                 *p++ = '\0';
     528             : 
     529             :                 /* defensive coding */
     530        1763 :                 if (packet->auth_data == NULL) {
     531           8 :                         packet->auth_data_len = 0;
     532             :                 }
     533        1763 :                 if (packet->auth_data_len > 0xFF) {
     534             :                         const char * const msg = "Authentication data too long. "
     535           0 :                                 "Won't fit into the buffer and will be truncated. Authentication will thus fail";
     536           0 :                         SET_CLIENT_ERROR(error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, msg);
     537           0 :                         php_error_docref(NULL, E_WARNING, "%s", msg);
     538           0 :                         DBG_RETURN(0);
     539             :                 }
     540             : 
     541        1763 :                 int1store(p, packet->auth_data_len);
     542        1763 :                 ++p;
     543             : /*!!!!! is the buffer big enough ??? */
     544        1763 :                 if (sizeof(buffer) < (packet->auth_data_len + (p - buffer))) {
     545           0 :                         DBG_ERR("the stack buffer was not enough!!");
     546           0 :                         DBG_RETURN(0);
     547             :                 }
     548        1763 :                 if (packet->auth_data_len) {
     549        1755 :                         memcpy(p, packet->auth_data, packet->auth_data_len);
     550        1755 :                         p+= packet->auth_data_len;
     551             :                 }
     552             : 
     553        1763 :                 if (packet->db) {
     554             :                         /* CLIENT_CONNECT_WITH_DB should have been set */
     555        1763 :                         size_t real_db_len = MIN(MYSQLND_MAX_ALLOWED_DB_LEN, packet->db_len);
     556        1763 :                         memcpy(p, packet->db, real_db_len);
     557        1763 :                         p+= real_db_len;
     558        1763 :                         *p++= '\0';
     559           0 :                 } else if (packet->is_change_user_packet) {
     560           0 :                         *p++= '\0';
     561             :                 }
     562             :                 /* no \0 for no DB */
     563             : 
     564        1763 :                 if (packet->is_change_user_packet) {
     565          75 :                         if (packet->charset_no) {
     566          75 :                                 int2store(p, packet->charset_no);
     567          75 :                                 p+= 2;
     568             :                         }
     569             :                 }
     570             : 
     571        1763 :                 if (packet->auth_plugin_name) {
     572        1763 :                         len = MIN(strlen(packet->auth_plugin_name), sizeof(buffer) - (p - buffer) - 1);
     573        1763 :                         memcpy(p, packet->auth_plugin_name, len);
     574        1763 :                         p+= len;
     575        1763 :                         *p++= '\0';
     576             :                 }
     577             : 
     578        1763 :                 if (packet->connect_attr && zend_hash_num_elements(packet->connect_attr)) {
     579           0 :                         size_t ca_payload_len = 0;
     580             : 
     581             :                         {
     582             :                                 zend_string * key;
     583             :                                 zval * entry_value;
     584           0 :                                 ZEND_HASH_FOREACH_STR_KEY_VAL(packet->connect_attr, key, entry_value) {
     585           0 :                                         if (key) { /* HASH_KEY_IS_STRING */
     586           0 :                                                 size_t value_len = Z_STRLEN_P(entry_value);
     587             : 
     588           0 :                                                 ca_payload_len += php_mysqlnd_net_store_length_size(ZSTR_LEN(key));
     589           0 :                                                 ca_payload_len += ZSTR_LEN(key);
     590           0 :                                                 ca_payload_len += php_mysqlnd_net_store_length_size(value_len);
     591           0 :                                                 ca_payload_len += value_len;
     592             :                                         }
     593             :                                 } ZEND_HASH_FOREACH_END();
     594             :                         }
     595             : 
     596           0 :                         if (sizeof(buffer) >= (ca_payload_len + php_mysqlnd_net_store_length_size(ca_payload_len) + (p - buffer))) {
     597           0 :                                 p = php_mysqlnd_net_store_length(p, ca_payload_len);
     598             : 
     599             :                                 {
     600             :                                         zend_string * key;
     601             :                                         zval * entry_value;
     602           0 :                                         ZEND_HASH_FOREACH_STR_KEY_VAL(packet->connect_attr, key, entry_value) {
     603           0 :                                                 if (key) { /* HASH_KEY_IS_STRING */
     604           0 :                                                         size_t value_len = Z_STRLEN_P(entry_value);
     605             : 
     606             :                                                         /* copy key */
     607           0 :                                                         p = php_mysqlnd_net_store_length(p, ZSTR_LEN(key));
     608           0 :                                                         memcpy(p, ZSTR_VAL(key), ZSTR_LEN(key));
     609           0 :                                                         p+= ZSTR_LEN(key);
     610             :                                                         /* copy value */
     611           0 :                                                         p = php_mysqlnd_net_store_length(p, value_len);
     612           0 :                                                         memcpy(p, Z_STRVAL_P(entry_value), value_len);
     613           0 :                                                         p+= value_len;
     614             :                                                 }
     615             :                                         } ZEND_HASH_FOREACH_END();
     616             :                                 }
     617             :                         } else {
     618             :                                 /* cannot put the data - skip */
     619             :                         }
     620             :                 }
     621             :         }
     622        1767 :         if (packet->is_change_user_packet) {
     623          75 :                 enum_func_status ret = FAIL;
     624          75 :                 const MYSQLND_CSTRING payload = {(char*) buffer + MYSQLND_HEADER_SIZE, p - (buffer + MYSQLND_HEADER_SIZE)};
     625          75 :                 const unsigned int silent = packet->silent;
     626          75 :                 struct st_mysqlnd_protocol_command * command = conn->command_factory(COM_CHANGE_USER, conn, payload, silent);
     627          75 :                 if (command) {
     628          75 :                         ret = command->run(command);
     629          75 :                         command->free_command(command);
     630             :                 }
     631             : 
     632          75 :                 DBG_RETURN(ret == PASS? (p - buffer - MYSQLND_HEADER_SIZE) : 0);
     633             :         } else {
     634        1692 :                 size_t sent = pfc->data->m.send(pfc, vio, buffer, p - buffer - MYSQLND_HEADER_SIZE, stats, error_info);
     635        1692 :                 if (!sent) {
     636           0 :                         SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
     637             :                 }
     638        1692 :                 DBG_RETURN(sent);
     639             :         }
     640             : }
     641             : /* }}} */
     642             : 
     643             : 
     644             : /* {{{ php_mysqlnd_auth_free_mem */
     645             : static
     646        3455 : void php_mysqlnd_auth_free_mem(void * _packet, zend_bool stack_allocation)
     647             : {
     648        3455 :         if (!stack_allocation) {
     649        3455 :                 MYSQLND_PACKET_AUTH * p = (MYSQLND_PACKET_AUTH *) _packet;
     650        3455 :                 mnd_pefree(p, p->header.persistent);
     651             :         }
     652        3455 : }
     653             : /* }}} */
     654             : 
     655             : 
     656             : #define AUTH_RESP_BUFFER_SIZE 2048
     657             : 
     658             : /* {{{ php_mysqlnd_auth_response_read */
     659             : static enum_func_status
     660        1688 : php_mysqlnd_auth_response_read(void * _packet)
     661             : {
     662        1688 :         register MYSQLND_PACKET_AUTH_RESPONSE * packet= (MYSQLND_PACKET_AUTH_RESPONSE *) _packet;
     663        1688 :         MYSQLND_ERROR_INFO * error_info = packet->header.error_info;
     664        1688 :         MYSQLND_PFC * pfc = packet->header.protocol_frame_codec;
     665        1688 :         MYSQLND_VIO * vio = packet->header.vio;
     666        1688 :         MYSQLND_STATS * stats = packet->header.stats;
     667        1688 :         MYSQLND_CONNECTION_STATE * connection_state = packet->header.connection_state;
     668             :         zend_uchar local_buf[AUTH_RESP_BUFFER_SIZE];
     669        1688 :         size_t buf_len = pfc->cmd_buffer.buffer? pfc->cmd_buffer.length: AUTH_RESP_BUFFER_SIZE;
     670        1688 :         zend_uchar *buf = pfc->cmd_buffer.buffer? (zend_uchar *) pfc->cmd_buffer.buffer : local_buf;
     671        1688 :         const zend_uchar * p = buf;
     672        1688 :         const zend_uchar * const begin = buf;
     673             : 
     674        1688 :         DBG_ENTER("php_mysqlnd_auth_response_read");
     675             : 
     676             :         /* leave space for terminating safety \0 */
     677        1688 :         buf_len--;
     678        1688 :         if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "OK", PROT_OK_PACKET)) {
     679           0 :                 DBG_RETURN(FAIL);
     680             :         }
     681        1688 :         BAIL_IF_NO_MORE_DATA;
     682             : 
     683             :         /*
     684             :           zero-terminate the buffer for safety. We are sure there is place for the \0
     685             :           because buf_len is -1 the size of the buffer pointed
     686             :         */
     687        1688 :         buf[packet->header.size] = '\0';
     688             : 
     689             :         /* Should be always 0x0 or ERROR_MARKER for error */
     690        1688 :         packet->response_code = uint1korr(p);
     691        1688 :         p++;
     692        1688 :         BAIL_IF_NO_MORE_DATA;
     693             : 
     694        1688 :         if (ERROR_MARKER == packet->response_code) {
     695          24 :                 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
     696             :                                                                                  packet->error, sizeof(packet->error),
     697             :                                                                                  &packet->error_no, packet->sqlstate
     698             :                                                                                 );
     699          24 :                 DBG_RETURN(PASS);
     700             :         }
     701        1664 :         if (0xFE == packet->response_code) {
     702             :                 /* Authentication Switch Response */
     703           0 :                 if (packet->header.size > (size_t) (p - buf)) {
     704           0 :                         packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE);
     705           0 :                         packet->new_auth_protocol_len = strlen(packet->new_auth_protocol);
     706           0 :                         p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */
     707             : 
     708           0 :                         packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf);
     709           0 :                         if (packet->new_auth_protocol_data_len) {
     710           0 :                                 packet->new_auth_protocol_data = mnd_emalloc(packet->new_auth_protocol_data_len);
     711           0 :                                 memcpy(packet->new_auth_protocol_data, p, packet->new_auth_protocol_data_len);
     712             :                         }
     713           0 :                         DBG_INF_FMT("The server requested switching auth plugin to : %s", packet->new_auth_protocol);
     714           0 :                         DBG_INF_FMT("Server salt : [%d][%.*s]", packet->new_auth_protocol_data_len, packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
     715             :                 }
     716             :         } else {
     717             :                 zend_ulong net_len;
     718             :                 /* Everything was fine! */
     719        1664 :                 packet->affected_rows  = php_mysqlnd_net_field_length_ll(&p);
     720        1664 :                 BAIL_IF_NO_MORE_DATA;
     721             : 
     722        1664 :                 packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p);
     723        1664 :                 BAIL_IF_NO_MORE_DATA;
     724             : 
     725        1664 :                 packet->server_status = uint2korr(p);
     726        1664 :                 p+= 2;
     727        1664 :                 BAIL_IF_NO_MORE_DATA;
     728             : 
     729        1664 :                 packet->warning_count = uint2korr(p);
     730        1664 :                 p+= 2;
     731        1664 :                 BAIL_IF_NO_MORE_DATA;
     732             : 
     733             :                 /* There is a message */
     734        1664 :                 if (packet->header.size > (size_t) (p - buf) && (net_len = php_mysqlnd_net_field_length(&p))) {
     735           0 :                         packet->message_len = MIN(net_len, buf_len - (p - begin));
     736           0 :                         packet->message = mnd_pestrndup((char *)p, packet->message_len, FALSE);
     737             :                 } else {
     738        1664 :                         packet->message = NULL;
     739        1664 :                         packet->message_len = 0;
     740             :                 }
     741             : 
     742        3328 :                 DBG_INF_FMT("OK packet: aff_rows=%lld last_ins_id=%pd server_status=%u warnings=%u",
     743        1664 :                                         packet->affected_rows, packet->last_insert_id, packet->server_status,
     744        1664 :                                         packet->warning_count);
     745             :         }
     746             : 
     747        1664 :         DBG_RETURN(PASS);
     748             : premature_end:
     749           0 :         DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size);
     750           0 :         php_error_docref(NULL, E_WARNING, "AUTH_RESPONSE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
     751           0 :                                          p - begin - packet->header.size);
     752           0 :         DBG_RETURN(FAIL);
     753             : }
     754             : /* }}} */
     755             : 
     756             : 
     757             : /* {{{ php_mysqlnd_auth_response_free_mem */
     758             : static void
     759        1688 : php_mysqlnd_auth_response_free_mem(void * _packet, zend_bool stack_allocation)
     760             : {
     761        1688 :         MYSQLND_PACKET_AUTH_RESPONSE * p = (MYSQLND_PACKET_AUTH_RESPONSE *) _packet;
     762        1688 :         if (p->message) {
     763           0 :                 mnd_efree(p->message);
     764           0 :                 p->message = NULL;
     765             :         }
     766        1688 :         if (p->new_auth_protocol) {
     767           0 :                 mnd_efree(p->new_auth_protocol);
     768           0 :                 p->new_auth_protocol = NULL;
     769             :         }
     770        1688 :         p->new_auth_protocol_len = 0;
     771             : 
     772        1688 :         if (p->new_auth_protocol_data) {
     773           0 :                 mnd_efree(p->new_auth_protocol_data);
     774           0 :                 p->new_auth_protocol_data = NULL;
     775             :         }
     776        1688 :         p->new_auth_protocol_data_len = 0;
     777             : 
     778        1688 :         if (!stack_allocation) {
     779        1688 :                 mnd_pefree(p, p->header.persistent);
     780             :         }
     781        1688 : }
     782             : /* }}} */
     783             : 
     784             : 
     785             : /* {{{ php_mysqlnd_change_auth_response_write */
     786             : static size_t
     787           0 : php_mysqlnd_change_auth_response_write(void * _packet)
     788             : {
     789           0 :         MYSQLND_PACKET_CHANGE_AUTH_RESPONSE *packet= (MYSQLND_PACKET_CHANGE_AUTH_RESPONSE *) _packet;
     790           0 :         MYSQLND_ERROR_INFO * error_info = packet->header.error_info;
     791           0 :         MYSQLND_PFC * pfc = packet->header.protocol_frame_codec;
     792           0 :         MYSQLND_VIO * vio = packet->header.vio;
     793           0 :         MYSQLND_STATS * stats = packet->header.stats;
     794           0 :         MYSQLND_CONNECTION_STATE * connection_state = packet->header.connection_state;
     795           0 :         zend_uchar * buffer = pfc->cmd_buffer.length >= packet->auth_data_len? pfc->cmd_buffer.buffer : mnd_emalloc(packet->auth_data_len);
     796           0 :         zend_uchar * p = buffer + MYSQLND_HEADER_SIZE; /* start after the header */
     797             : 
     798           0 :         DBG_ENTER("php_mysqlnd_change_auth_response_write");
     799             : 
     800           0 :         if (packet->auth_data_len) {
     801           0 :                 memcpy(p, packet->auth_data, packet->auth_data_len);
     802           0 :                 p+= packet->auth_data_len;
     803             :         }
     804             : 
     805             :         {
     806           0 :                 size_t sent = pfc->data->m.send(pfc, vio, buffer, p - buffer - MYSQLND_HEADER_SIZE, stats, error_info);
     807           0 :                 if (buffer != pfc->cmd_buffer.buffer) {
     808           0 :                         mnd_efree(buffer);
     809             :                 }
     810           0 :                 if (!sent) {
     811           0 :                         SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
     812             :                 }
     813           0 :                 DBG_RETURN(sent);
     814             :         }
     815             : }
     816             : /* }}} */
     817             : 
     818             : 
     819             : /* {{{ php_mysqlnd_change_auth_response_free_mem */
     820             : static void
     821           0 : php_mysqlnd_change_auth_response_free_mem(void * _packet, zend_bool stack_allocation)
     822             : {
     823           0 :         if (!stack_allocation) {
     824           0 :                 MYSQLND_PACKET_CHANGE_AUTH_RESPONSE * p = (MYSQLND_PACKET_CHANGE_AUTH_RESPONSE *) _packet;
     825           0 :                 mnd_pefree(p, p->header.persistent);
     826             :         }
     827           0 : }
     828             : /* }}} */
     829             : 
     830             : 
     831             : #define OK_BUFFER_SIZE 2048
     832             : 
     833             : /* {{{ php_mysqlnd_ok_read */
     834             : static enum_func_status
     835          97 : php_mysqlnd_ok_read(void * _packet)
     836             : {
     837          97 :         register MYSQLND_PACKET_OK *packet= (MYSQLND_PACKET_OK *) _packet;
     838          97 :         MYSQLND_ERROR_INFO * error_info = packet->header.error_info;
     839          97 :         MYSQLND_PFC * pfc = packet->header.protocol_frame_codec;
     840          97 :         MYSQLND_VIO * vio = packet->header.vio;
     841          97 :         MYSQLND_STATS * stats = packet->header.stats;
     842          97 :         MYSQLND_CONNECTION_STATE * connection_state = packet->header.connection_state;
     843             :         zend_uchar local_buf[OK_BUFFER_SIZE];
     844          97 :         size_t buf_len = pfc->cmd_buffer.buffer? pfc->cmd_buffer.length : OK_BUFFER_SIZE;
     845          97 :         zend_uchar * buf = pfc->cmd_buffer.buffer? (zend_uchar *) pfc->cmd_buffer.buffer : local_buf;
     846          97 :         const zend_uchar * p = buf;
     847          97 :         const zend_uchar * const begin = buf;
     848             :         zend_ulong net_len;
     849             : 
     850          97 :         DBG_ENTER("php_mysqlnd_ok_read");
     851             : 
     852          97 :         if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "OK", PROT_OK_PACKET)) {
     853           0 :                 DBG_RETURN(FAIL);
     854             :         }
     855          97 :         BAIL_IF_NO_MORE_DATA;
     856             : 
     857             :         /* Should be always 0x0 or ERROR_MARKER for error */
     858          97 :         packet->field_count = uint1korr(p);
     859          97 :         p++;
     860          97 :         BAIL_IF_NO_MORE_DATA;
     861             : 
     862          97 :         if (ERROR_MARKER == packet->field_count) {
     863           8 :                 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
     864             :                                                                                  packet->error, sizeof(packet->error),
     865             :                                                                                  &packet->error_no, packet->sqlstate
     866             :                                                                                 );
     867           8 :                 DBG_RETURN(PASS);
     868             :         }
     869             :         /* Everything was fine! */
     870          89 :         packet->affected_rows  = php_mysqlnd_net_field_length_ll(&p);
     871          89 :         BAIL_IF_NO_MORE_DATA;
     872             : 
     873          89 :         packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p);
     874          89 :         BAIL_IF_NO_MORE_DATA;
     875             : 
     876          89 :         packet->server_status = uint2korr(p);
     877          89 :         p+= 2;
     878          89 :         BAIL_IF_NO_MORE_DATA;
     879             : 
     880          89 :         packet->warning_count = uint2korr(p);
     881          89 :         p+= 2;
     882          89 :         BAIL_IF_NO_MORE_DATA;
     883             : 
     884             :         /* There is a message */
     885         101 :         if (packet->header.size > (size_t) (p - buf) && (net_len = php_mysqlnd_net_field_length(&p))) {
     886          12 :                 packet->message_len = MIN(net_len, buf_len - (p - begin));
     887          12 :                 packet->message = mnd_pestrndup((char *)p, packet->message_len, FALSE);
     888             :         } else {
     889          77 :                 packet->message = NULL;
     890          77 :                 packet->message_len = 0;
     891             :         }
     892             : 
     893         178 :         DBG_INF_FMT("OK packet: aff_rows=%lld last_ins_id=%ld server_status=%u warnings=%u",
     894          89 :                                 packet->affected_rows, packet->last_insert_id, packet->server_status,
     895          89 :                                 packet->warning_count);
     896             : 
     897          89 :         BAIL_IF_NO_MORE_DATA;
     898             : 
     899          89 :         DBG_RETURN(PASS);
     900             : premature_end:
     901           0 :         DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size);
     902           0 :         php_error_docref(NULL, E_WARNING, "OK packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
     903           0 :                                          p - begin - packet->header.size);
     904           0 :         DBG_RETURN(FAIL);
     905             : }
     906             : /* }}} */
     907             : 
     908             : 
     909             : /* {{{ php_mysqlnd_ok_free_mem */
     910             : static void
     911          97 : php_mysqlnd_ok_free_mem(void * _packet, zend_bool stack_allocation)
     912             : {
     913          97 :         MYSQLND_PACKET_OK *p= (MYSQLND_PACKET_OK *) _packet;
     914          97 :         if (p->message) {
     915          12 :                 mnd_efree(p->message);
     916          12 :                 p->message = NULL;
     917             :         }
     918          97 :         if (!stack_allocation) {
     919          97 :                 mnd_pefree(p, p->header.persistent);
     920             :         }
     921          97 : }
     922             : /* }}} */
     923             : 
     924             : 
     925             : /* {{{ php_mysqlnd_eof_read */
     926             : static enum_func_status
     927        7728 : php_mysqlnd_eof_read(void * _packet)
     928             : {
     929             :         /*
     930             :           EOF packet is since 4.1 five bytes long,
     931             :           but we can get also an error, make it bigger.
     932             : 
     933             :           Error : error_code + '#' + sqlstate + MYSQLND_ERRMSG_SIZE
     934             :         */
     935        7728 :         MYSQLND_PACKET_EOF *packet= (MYSQLND_PACKET_EOF *) _packet;
     936        7728 :         MYSQLND_ERROR_INFO * error_info = packet->header.error_info;
     937        7728 :         MYSQLND_PFC * pfc = packet->header.protocol_frame_codec;
     938        7728 :         MYSQLND_VIO * vio = packet->header.vio;
     939        7728 :         MYSQLND_STATS * stats = packet->header.stats;
     940        7728 :         MYSQLND_CONNECTION_STATE * connection_state = packet->header.connection_state;
     941        7728 :         size_t buf_len = pfc->cmd_buffer.length;
     942        7728 :         zend_uchar * buf = (zend_uchar *) pfc->cmd_buffer.buffer;
     943        7728 :         const zend_uchar * p = buf;
     944        7728 :         const zend_uchar * const begin = buf;
     945             : 
     946        7728 :         DBG_ENTER("php_mysqlnd_eof_read");
     947             : 
     948        7728 :         if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "EOF", PROT_EOF_PACKET)) {
     949           0 :                 DBG_RETURN(FAIL);
     950             :         }
     951        7728 :         BAIL_IF_NO_MORE_DATA;
     952             : 
     953             :         /* Should be always EODATA_MARKER */
     954        7728 :         packet->field_count = uint1korr(p);
     955        7728 :         p++;
     956        7728 :         BAIL_IF_NO_MORE_DATA;
     957             : 
     958        7728 :         if (ERROR_MARKER == packet->field_count) {
     959           2 :                 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
     960             :                                                                                  packet->error, sizeof(packet->error),
     961             :                                                                                  &packet->error_no, packet->sqlstate
     962             :                                                                                 );
     963           2 :                 DBG_RETURN(PASS);
     964             :         }
     965             : 
     966             :         /*
     967             :                 4.1 sends 1 byte EOF packet after metadata of
     968             :                 PREPARE/EXECUTE but 5 bytes after the result. This is not
     969             :                 according to the Docs@Forge!!!
     970             :         */
     971        7726 :         if (packet->header.size > 1) {
     972        7726 :                 packet->warning_count = uint2korr(p);
     973        7726 :                 p+= 2;
     974        7726 :                 BAIL_IF_NO_MORE_DATA;
     975             : 
     976        7726 :                 packet->server_status = uint2korr(p);
     977        7726 :                 p+= 2;
     978        7726 :                 BAIL_IF_NO_MORE_DATA;
     979             :         } else {
     980           0 :                 packet->warning_count = 0;
     981           0 :                 packet->server_status = 0;
     982             :         }
     983             : 
     984        7726 :         BAIL_IF_NO_MORE_DATA;
     985             : 
     986       23178 :         DBG_INF_FMT("EOF packet: fields=%u status=%u warnings=%u",
     987       23178 :                                 packet->field_count, packet->server_status, packet->warning_count);
     988             : 
     989        7726 :         DBG_RETURN(PASS);
     990             : premature_end:
     991           0 :         DBG_ERR_FMT("EOF packet %d bytes shorter than expected", p - begin - packet->header.size);
     992           0 :         php_error_docref(NULL, E_WARNING, "EOF packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
     993           0 :                                          p - begin - packet->header.size);
     994           0 :         DBG_RETURN(FAIL);
     995             : }
     996             : /* }}} */
     997             : 
     998             : 
     999             : /* {{{ php_mysqlnd_eof_free_mem */
    1000             : static
    1001        7728 : void php_mysqlnd_eof_free_mem(void * _packet, zend_bool stack_allocation)
    1002             : {
    1003        7728 :         if (!stack_allocation) {
    1004        7728 :                 mnd_pefree(_packet, ((MYSQLND_PACKET_EOF *)_packet)->header.persistent);
    1005             :         }
    1006        7728 : }
    1007             : /* }}} */
    1008             : 
    1009             : 
    1010             : /* {{{ php_mysqlnd_cmd_write */
    1011       37118 : size_t php_mysqlnd_cmd_write(void * _packet)
    1012             : {
    1013             :         /* Let's have some space, which we can use, if not enough, we will allocate new buffer */
    1014       37118 :         MYSQLND_PACKET_COMMAND * packet= (MYSQLND_PACKET_COMMAND *) _packet;
    1015       37118 :         MYSQLND_ERROR_INFO * error_info = packet->header.error_info;
    1016       37118 :         MYSQLND_PFC * pfc = packet->header.protocol_frame_codec;
    1017       37118 :         MYSQLND_VIO * vio = packet->header.vio;
    1018       37118 :         MYSQLND_STATS * stats = packet->header.stats;
    1019       37118 :         MYSQLND_CONNECTION_STATE * connection_state = packet->header.connection_state;
    1020       37118 :         unsigned int error_reporting = EG(error_reporting);
    1021       37118 :         size_t sent = 0;
    1022             : 
    1023       37118 :         DBG_ENTER("php_mysqlnd_cmd_write");
    1024             :         /*
    1025             :           Reset packet_no, or we will get bad handshake!
    1026             :           Every command starts a new TX and packet numbers are reset to 0.
    1027             :         */
    1028       37118 :         pfc->data->m.reset(pfc, stats, error_info);
    1029             : 
    1030       37118 :         if (error_reporting) {
    1031       36631 :                 EG(error_reporting) = 0;
    1032             :         }
    1033             : 
    1034       37118 :         MYSQLND_INC_CONN_STATISTIC(stats, STAT_PACKETS_SENT_CMD);
    1035             : 
    1036             : #ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
    1037             :         vio->data->m.consume_uneaten_data(vio, packet->command);
    1038             : #endif
    1039             : 
    1040       38812 :         if (!packet->argument.s || !packet->argument.l) {
    1041             :                 zend_uchar buffer[MYSQLND_HEADER_SIZE + 1];
    1042             : 
    1043        1694 :                 int1store(buffer + MYSQLND_HEADER_SIZE, packet->command);
    1044        1694 :                 sent = pfc->data->m.send(pfc, vio, buffer, 1, stats, error_info);
    1045             :         } else {
    1046       35424 :                 size_t tmp_len = packet->argument.l + 1 + MYSQLND_HEADER_SIZE;
    1047             :                 zend_uchar *tmp, *p;
    1048       35424 :                 tmp = (tmp_len > pfc->cmd_buffer.length)? mnd_emalloc(tmp_len):pfc->cmd_buffer.buffer;
    1049       35424 :                 if (!tmp) {
    1050           0 :                         goto end;
    1051             :                 }
    1052       35424 :                 p = tmp + MYSQLND_HEADER_SIZE; /* skip the header */
    1053             : 
    1054       35424 :                 int1store(p, packet->command);
    1055       35424 :                 p++;
    1056             : 
    1057       35424 :                 memcpy(p, packet->argument.s, packet->argument.l);
    1058             : 
    1059       35424 :                 sent = pfc->data->m.send(pfc, vio, tmp, tmp_len - MYSQLND_HEADER_SIZE, stats, error_info);
    1060       35424 :                 if (tmp != pfc->cmd_buffer.buffer) {
    1061          38 :                         MYSQLND_INC_CONN_STATISTIC(stats, STAT_CMD_BUFFER_TOO_SMALL);
    1062          38 :                         mnd_efree(tmp);
    1063             :                 }
    1064             :         }
    1065             : end:
    1066       37118 :         if (error_reporting) {
    1067             :                 /* restore error reporting */
    1068       36631 :                 EG(error_reporting) = error_reporting;
    1069             :         }
    1070       37118 :         if (!sent) {
    1071           9 :                 SET_CONNECTION_STATE(connection_state, CONN_QUIT_SENT);
    1072             :         }
    1073       37118 :         DBG_RETURN(sent);
    1074             : }
    1075             : /* }}} */
    1076             : 
    1077             : 
    1078             : /* {{{ php_mysqlnd_cmd_free_mem */
    1079             : static
    1080       37118 : void php_mysqlnd_cmd_free_mem(void * _packet, zend_bool stack_allocation)
    1081             : {
    1082       37118 :         if (!stack_allocation) {
    1083       37118 :                 MYSQLND_PACKET_COMMAND * p = (MYSQLND_PACKET_COMMAND *) _packet;
    1084       37118 :                 mnd_pefree(p, p->header.persistent);
    1085             :         }
    1086       37118 : }
    1087             : /* }}} */
    1088             : 
    1089             : 
    1090             : /* {{{ php_mysqlnd_rset_header_read */
    1091             : static enum_func_status
    1092       26853 : php_mysqlnd_rset_header_read(void * _packet)
    1093             : {
    1094       26853 :         MYSQLND_PACKET_RSET_HEADER * packet= (MYSQLND_PACKET_RSET_HEADER *) _packet;
    1095       26853 :         MYSQLND_ERROR_INFO * error_info = packet->header.error_info;
    1096       26853 :         MYSQLND_PFC * pfc = packet->header.protocol_frame_codec;
    1097       26853 :         MYSQLND_VIO * vio = packet->header.vio;
    1098       26853 :         MYSQLND_STATS * stats = packet->header.stats;
    1099       26853 :         MYSQLND_CONNECTION_STATE * connection_state = packet->header.connection_state;
    1100       26853 :         enum_func_status ret = PASS;
    1101       26853 :         size_t buf_len = pfc->cmd_buffer.length;
    1102       26853 :         zend_uchar * buf = (zend_uchar *) pfc->cmd_buffer.buffer;
    1103       26853 :         const zend_uchar * p = buf;
    1104       26853 :         const zend_uchar * const begin = buf;
    1105             :         size_t len;
    1106             : 
    1107       26853 :         DBG_ENTER("php_mysqlnd_rset_header_read");
    1108             : 
    1109       26853 :         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)) {
    1110           1 :                 DBG_RETURN(FAIL);
    1111             :         }
    1112       26852 :         BAIL_IF_NO_MORE_DATA;
    1113             : 
    1114             :         /*
    1115             :           Don't increment. First byte is ERROR_MARKER on error, but otherwise is starting byte
    1116             :           of encoded sequence for length.
    1117             :         */
    1118       26852 :         if (ERROR_MARKER == *p) {
    1119             :                 /* Error */
    1120         800 :                 p++;
    1121         800 :                 BAIL_IF_NO_MORE_DATA;
    1122         800 :                 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
    1123             :                                                                                  packet->error_info.error, sizeof(packet->error_info.error),
    1124             :                                                                                  &packet->error_info.error_no, packet->error_info.sqlstate
    1125             :                                                                                 );
    1126         800 :                 DBG_RETURN(PASS);
    1127             :         }
    1128             : 
    1129       26052 :         packet->field_count = php_mysqlnd_net_field_length(&p);
    1130       26052 :         BAIL_IF_NO_MORE_DATA;
    1131             : 
    1132       26051 :         switch (packet->field_count) {
    1133             :                 case MYSQLND_NULL_LENGTH:
    1134          12 :                         DBG_INF("LOAD LOCAL");
    1135             :                         /*
    1136             :                           First byte in the packet is the field count.
    1137             :                           Thus, the name is size - 1. And we add 1 for a trailing \0.
    1138             :                           Because we have BAIL_IF_NO_MORE_DATA before the switch, we are guaranteed
    1139             :                           that packet->header.size is > 0. Which means that len can't underflow, that
    1140             :                           would lead to 0 byte allocation but 2^32 or 2^64 bytes copied.
    1141             :                         */
    1142          12 :                         len = packet->header.size - 1;
    1143          12 :                         packet->info_or_local_file.s = mnd_emalloc(len + 1);
    1144          12 :                         if (packet->info_or_local_file.s) {
    1145          12 :                                 memcpy(packet->info_or_local_file.s, p, len);
    1146          12 :                                 packet->info_or_local_file.s[len] = '\0';
    1147          12 :                                 packet->info_or_local_file.l = len;
    1148             :                         } else {
    1149           0 :                                 SET_OOM_ERROR(error_info);
    1150           0 :                                 ret = FAIL;
    1151             :                         }
    1152          12 :                         break;
    1153             :                 case 0x00:
    1154       21601 :                         DBG_INF("UPSERT");
    1155       21601 :                         packet->affected_rows = php_mysqlnd_net_field_length_ll(&p);
    1156       21601 :                         BAIL_IF_NO_MORE_DATA;
    1157             : 
    1158       21601 :                         packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p);
    1159       21601 :                         BAIL_IF_NO_MORE_DATA;
    1160             : 
    1161       21601 :                         packet->server_status = uint2korr(p);
    1162       21601 :                         p+=2;
    1163       21601 :                         BAIL_IF_NO_MORE_DATA;
    1164             : 
    1165       21601 :                         packet->warning_count = uint2korr(p);
    1166       21601 :                         p+=2;
    1167       21601 :                         BAIL_IF_NO_MORE_DATA;
    1168             :                         /* Check for additional textual data */
    1169       21601 :                         if (packet->header.size  > (size_t) (p - buf) && (len = php_mysqlnd_net_field_length(&p))) {
    1170         344 :                                 packet->info_or_local_file.s = mnd_emalloc(len + 1);
    1171         344 :                                 if (packet->info_or_local_file.s) {
    1172         344 :                                         memcpy(packet->info_or_local_file.s, p, len);
    1173         344 :                                         packet->info_or_local_file.s[len] = '\0';
    1174         344 :                                         packet->info_or_local_file.l = len;
    1175             :                                 } else {
    1176           0 :                                         SET_OOM_ERROR(error_info);
    1177           0 :                                         ret = FAIL;
    1178             :                                 }
    1179             :                         }
    1180       43202 :                         DBG_INF_FMT("affected_rows=%llu last_insert_id=%llu server_status=%u warning_count=%u",
    1181             :                                                 packet->affected_rows, packet->last_insert_id,
    1182       43202 :                                                 packet->server_status, packet->warning_count);
    1183       21601 :                         break;
    1184             :                 default:
    1185        4438 :                         DBG_INF("SELECT");
    1186             :                         /* Result set */
    1187             :                         break;
    1188             :         }
    1189       26051 :         BAIL_IF_NO_MORE_DATA;
    1190             : 
    1191       26051 :         DBG_RETURN(ret);
    1192             : premature_end:
    1193           1 :         DBG_ERR_FMT("RSET_HEADER packet %d bytes shorter than expected", p - begin - packet->header.size);
    1194           1 :         php_error_docref(NULL, E_WARNING, "RSET_HEADER packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
    1195           1 :                                          p - begin - packet->header.size);
    1196           1 :         DBG_RETURN(FAIL);
    1197             : }
    1198             : /* }}} */
    1199             : 
    1200             : 
    1201             : /* {{{ php_mysqlnd_rset_header_free_mem */
    1202             : static
    1203       26853 : void php_mysqlnd_rset_header_free_mem(void * _packet, zend_bool stack_allocation)
    1204             : {
    1205       26853 :         MYSQLND_PACKET_RSET_HEADER *p= (MYSQLND_PACKET_RSET_HEADER *) _packet;
    1206       26853 :         DBG_ENTER("php_mysqlnd_rset_header_free_mem");
    1207       26853 :         if (p->info_or_local_file.s) {
    1208         356 :                 mnd_efree(p->info_or_local_file.s);
    1209         356 :                 p->info_or_local_file.s = NULL;
    1210             :         }
    1211       26853 :         if (!stack_allocation) {
    1212       26853 :                 mnd_pefree(p, p->header.persistent);
    1213             :         }
    1214       26853 :         DBG_VOID_RETURN;
    1215             : }
    1216             : /* }}} */
    1217             : 
    1218             : static size_t rset_field_offsets[] =
    1219             : {
    1220             :         STRUCT_OFFSET(MYSQLND_FIELD, catalog),
    1221             :         STRUCT_OFFSET(MYSQLND_FIELD, catalog_length),
    1222             :         STRUCT_OFFSET(MYSQLND_FIELD, db),
    1223             :         STRUCT_OFFSET(MYSQLND_FIELD, db_length),
    1224             :         STRUCT_OFFSET(MYSQLND_FIELD, table),
    1225             :         STRUCT_OFFSET(MYSQLND_FIELD, table_length),
    1226             :         STRUCT_OFFSET(MYSQLND_FIELD, org_table),
    1227             :         STRUCT_OFFSET(MYSQLND_FIELD, org_table_length),
    1228             :         STRUCT_OFFSET(MYSQLND_FIELD, name),
    1229             :         STRUCT_OFFSET(MYSQLND_FIELD, name_length),
    1230             :         STRUCT_OFFSET(MYSQLND_FIELD, org_name),
    1231             :         STRUCT_OFFSET(MYSQLND_FIELD, org_name_length),
    1232             : };
    1233             : 
    1234             : 
    1235             : /* {{{ php_mysqlnd_rset_field_read */
    1236             : static enum_func_status
    1237      157700 : php_mysqlnd_rset_field_read(void * _packet)
    1238             : {
    1239             :         /* Should be enough for the metadata of a single row */
    1240      157700 :         MYSQLND_PACKET_RES_FIELD *packet = (MYSQLND_PACKET_RES_FIELD *) _packet;
    1241      157700 :         MYSQLND_ERROR_INFO * error_info = packet->header.error_info;
    1242      157700 :         MYSQLND_PFC * pfc = packet->header.protocol_frame_codec;
    1243      157700 :         MYSQLND_VIO * vio = packet->header.vio;
    1244      157700 :         MYSQLND_STATS * stats = packet->header.stats;
    1245      157700 :         MYSQLND_CONNECTION_STATE * connection_state = packet->header.connection_state;
    1246      157700 :         size_t buf_len = pfc->cmd_buffer.length, total_len = 0;
    1247      157700 :         zend_uchar * buf = (zend_uchar *) pfc->cmd_buffer.buffer;
    1248      157700 :         const zend_uchar * p = buf;
    1249      157700 :         const zend_uchar * const begin = buf;
    1250             :         char *root_ptr;
    1251             :         zend_ulong len;
    1252             :         MYSQLND_FIELD *meta;
    1253      157700 :         unsigned int i, field_count = sizeof(rset_field_offsets)/sizeof(size_t);
    1254             : 
    1255      157700 :         DBG_ENTER("php_mysqlnd_rset_field_read");
    1256             : 
    1257      157700 :         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)) {
    1258           0 :                 DBG_RETURN(FAIL);
    1259             :         }
    1260             : 
    1261      157700 :         if (packet->skip_parsing) {
    1262      134415 :                 DBG_RETURN(PASS);
    1263             :         }
    1264             : 
    1265       23285 :         BAIL_IF_NO_MORE_DATA;
    1266       23285 :         if (ERROR_MARKER == *p) {
    1267             :                 /* Error */
    1268           0 :                 p++;
    1269           0 :                 BAIL_IF_NO_MORE_DATA;
    1270           0 :                 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
    1271             :                                                                                  packet->error_info.error, sizeof(packet->error_info.error),
    1272             :                                                                                  &packet->error_info.error_no, packet->error_info.sqlstate
    1273             :                                                                                 );
    1274           0 :                 DBG_ERR_FMT("Server error : (%u) %s", packet->error_info.error_no, packet->error_info.error);
    1275           0 :                 DBG_RETURN(PASS);
    1276       23285 :         } else if (EODATA_MARKER == *p && packet->header.size < 8) {
    1277             :                 /* Premature EOF. That should be COM_FIELD_LIST. But we don't support COM_FIELD_LIST anymore, thus this should not happen */
    1278           0 :                 DBG_INF("Premature EOF. That should be COM_FIELD_LIST");
    1279           0 :                 DBG_RETURN(PASS);
    1280             :         }
    1281             : 
    1282       23285 :         meta = packet->metadata;
    1283             : 
    1284      162995 :         for (i = 0; i < field_count; i += 2) {
    1285      139710 :                 len = php_mysqlnd_net_field_length(&p);
    1286      139710 :                 BAIL_IF_NO_MORE_DATA;
    1287      139710 :                 switch ((len)) {
    1288             :                         case 0:
    1289       23070 :                                 *(const char **)(((char*)meta) + rset_field_offsets[i]) = mysqlnd_empty_string;
    1290       23070 :                                 *(unsigned int *)(((char*)meta) + rset_field_offsets[i+1]) = 0;
    1291       23070 :                                 break;
    1292             :                         case MYSQLND_NULL_LENGTH:
    1293           0 :                                 goto faulty_or_fake;
    1294             :                         default:
    1295      116640 :                                 *(const char **)(((char *)meta) + rset_field_offsets[i]) = (const char *)p;
    1296      116640 :                                 *(unsigned int *)(((char*)meta) + rset_field_offsets[i+1]) = len;
    1297      116640 :                                 p += len;
    1298      116640 :                                 total_len += len + 1;
    1299             :                                 break;
    1300             :                 }
    1301      139710 :                 BAIL_IF_NO_MORE_DATA;
    1302             :         }
    1303             : 
    1304             :         /* 1 byte length */
    1305       23285 :         if (12 != *p) {
    1306           0 :                 DBG_ERR_FMT("Protocol error. Server sent false length. Expected 12 got %d", (int) *p);
    1307           0 :                 php_error_docref(NULL, E_WARNING, "Protocol error. Server sent false length. Expected 12");
    1308             :         }
    1309             : 
    1310       23285 :         p++;
    1311       23285 :         BAIL_IF_NO_MORE_DATA;
    1312             : 
    1313       23285 :         meta->charsetnr = uint2korr(p);
    1314       23285 :         p += 2;
    1315       23285 :         BAIL_IF_NO_MORE_DATA;
    1316             : 
    1317       23285 :         meta->length = uint4korr(p);
    1318       23285 :         p += 4;
    1319       23285 :         BAIL_IF_NO_MORE_DATA;
    1320             : 
    1321       23285 :         meta->type = uint1korr(p);
    1322       23285 :         p += 1;
    1323       23285 :         BAIL_IF_NO_MORE_DATA;
    1324             : 
    1325       23285 :         meta->flags = uint2korr(p);
    1326       23285 :         p += 2;
    1327       23285 :         BAIL_IF_NO_MORE_DATA;
    1328             : 
    1329       23285 :         meta->decimals = uint1korr(p);
    1330       23285 :         p += 1;
    1331       23285 :         BAIL_IF_NO_MORE_DATA;
    1332             : 
    1333             :         /* 2 byte filler */
    1334       23285 :         p +=2;
    1335       23285 :         BAIL_IF_NO_MORE_DATA;
    1336             : 
    1337             :         /* Should we set NUM_FLAG (libmysql does it) ? */
    1338       46804 :         if (
    1339       23285 :                 (meta->type <= MYSQL_TYPE_INT24 &&
    1340       10637 :                         (meta->type != MYSQL_TYPE_TIMESTAMP || meta->length == 14 || meta->length == 8)
    1341       12882 :                 ) || meta->type == MYSQL_TYPE_YEAR)
    1342             :         {
    1343       10446 :                 meta->flags |= NUM_FLAG;
    1344             :         }
    1345             : 
    1346             : 
    1347             :         /*
    1348             :           def could be empty, thus don't allocate on the root.
    1349             :           NULL_LENGTH (0xFB) comes from COM_FIELD_LIST when the default value is NULL.
    1350             :           Otherwise the string is length encoded.
    1351             :         */
    1352       23285 :         if (packet->header.size > (size_t) (p - buf) &&
    1353           0 :                 (len = php_mysqlnd_net_field_length(&p)) &&
    1354             :                 len != MYSQLND_NULL_LENGTH)
    1355             :         {
    1356           0 :                 BAIL_IF_NO_MORE_DATA;
    1357           0 :                 DBG_INF_FMT("Def found, length %lu, persistent=%u", len, packet->persistent_alloc);
    1358           0 :                 meta->def = mnd_pemalloc(len + 1, packet->persistent_alloc);
    1359           0 :                 if (!meta->def) {
    1360           0 :                         SET_OOM_ERROR(error_info);
    1361           0 :                         DBG_RETURN(FAIL);
    1362             :                 }
    1363           0 :                 memcpy(meta->def, p, len);
    1364           0 :                 meta->def[len] = '\0';
    1365           0 :                 meta->def_length = len;
    1366           0 :                 p += len;
    1367             :         }
    1368             : 
    1369       23285 :         root_ptr = meta->root = mnd_pemalloc(total_len, packet->persistent_alloc);
    1370       23285 :         if (!root_ptr) {
    1371           0 :                 SET_OOM_ERROR(error_info);
    1372           0 :                 DBG_RETURN(FAIL);
    1373             :         }
    1374             : 
    1375       23285 :         meta->root_len = total_len;
    1376             : 
    1377       23285 :         if (meta->name != mysqlnd_empty_string) {
    1378       46554 :                 meta->sname = zend_string_init(meta->name, meta->name_length, packet->persistent_alloc);
    1379             :         } else {
    1380           8 :                 meta->sname = ZSTR_EMPTY_ALLOC();
    1381             :         }
    1382       23285 :         meta->name = ZSTR_VAL(meta->sname);
    1383       23285 :         meta->name_length = ZSTR_LEN(meta->sname);
    1384             : 
    1385             :         /* Now do allocs */
    1386       23285 :         if (meta->catalog && meta->catalog != mysqlnd_empty_string) {
    1387       23285 :                 len = meta->catalog_length;
    1388       23285 :                 meta->catalog = memcpy(root_ptr, meta->catalog, len);
    1389       23285 :                 *(root_ptr +=len) = '\0';
    1390       23285 :                 root_ptr++;
    1391             :         }
    1392             : 
    1393       23285 :         if (meta->db && meta->db != mysqlnd_empty_string) {
    1394       17387 :                 len = meta->db_length;
    1395       17387 :                 meta->db = memcpy(root_ptr, meta->db, len);
    1396       17387 :                 *(root_ptr +=len) = '\0';
    1397       17387 :                 root_ptr++;
    1398             :         }
    1399             : 
    1400       23285 :         if (meta->table && meta->table != mysqlnd_empty_string) {
    1401       17634 :                 len = meta->table_length;
    1402       17634 :                 meta->table = memcpy(root_ptr, meta->table, len);
    1403       17634 :                 *(root_ptr +=len) = '\0';
    1404       17634 :                 root_ptr++;
    1405             :         }
    1406             : 
    1407       23285 :         if (meta->org_table && meta->org_table != mysqlnd_empty_string) {
    1408       17387 :                 len = meta->org_table_length;
    1409       17387 :                 meta->org_table = memcpy(root_ptr, meta->org_table, len);
    1410       17387 :                 *(root_ptr +=len) = '\0';
    1411       17387 :                 root_ptr++;
    1412             :         }
    1413             : 
    1414       23285 :         if (meta->org_name && meta->org_name != mysqlnd_empty_string) {
    1415       17670 :                 len = meta->org_name_length;
    1416       17670 :                 meta->org_name = memcpy(root_ptr, meta->org_name, len);
    1417       17670 :                 *(root_ptr +=len) = '\0';
    1418       17670 :                 root_ptr++;
    1419             :         }
    1420             : 
    1421       23285 :         DBG_INF_FMT("allocing root. persistent=%u", packet->persistent_alloc);
    1422             : 
    1423       23285 :         DBG_INF_FMT("FIELD=[%s.%s.%s]", meta->db? meta->db:"*NA*", meta->table? meta->table:"*NA*",
    1424       23285 :                                 meta->name? meta->name:"*NA*");
    1425             : 
    1426       23285 :         DBG_RETURN(PASS);
    1427             : 
    1428             : faulty_or_fake:
    1429           0 :         DBG_ERR_FMT("Protocol error. Server sent NULL_LENGTH. The server is faulty");
    1430           0 :         php_error_docref(NULL, E_WARNING, "Protocol error. Server sent NULL_LENGTH."
    1431             :                                          " The server is faulty");
    1432           0 :         DBG_RETURN(FAIL);
    1433             : premature_end:
    1434           0 :         DBG_ERR_FMT("RSET field packet %d bytes shorter than expected", p - begin - packet->header.size);
    1435           0 :         php_error_docref(NULL, E_WARNING, "Result set field packet "MYSQLND_SZ_T_SPEC" bytes "
    1436           0 :                                         "shorter than expected", p - begin - packet->header.size);
    1437           0 :         DBG_RETURN(FAIL);
    1438             : }
    1439             : /* }}} */
    1440             : 
    1441             : 
    1442             : /* {{{ php_mysqlnd_rset_field_free_mem */
    1443             : static
    1444        7694 : void php_mysqlnd_rset_field_free_mem(void * _packet, zend_bool stack_allocation)
    1445             : {
    1446        7694 :         MYSQLND_PACKET_RES_FIELD *p = (MYSQLND_PACKET_RES_FIELD *) _packet;
    1447             :         /* p->metadata was passed to us as temporal buffer */
    1448        7694 :         if (!stack_allocation) {
    1449        7694 :                 mnd_pefree(p, p->header.persistent);
    1450             :         }
    1451        7694 : }
    1452             : /* }}} */
    1453             : 
    1454             : 
    1455             : /* {{{ php_mysqlnd_read_row_ex */
    1456             : static enum_func_status
    1457       91516 : php_mysqlnd_read_row_ex(MYSQLND_PFC * pfc,
    1458             :                                                 MYSQLND_VIO * vio,
    1459             :                                                 MYSQLND_STATS * stats,
    1460             :                                                 MYSQLND_ERROR_INFO * error_info,
    1461             :                                                 MYSQLND_MEMORY_POOL * result_set_memory_pool,
    1462             :                                                 MYSQLND_MEMORY_POOL_CHUNK ** buffer,
    1463             :                                                 size_t * data_size, zend_bool persistent_alloc,
    1464             :                                                 unsigned int prealloc_more_bytes)
    1465             : {
    1466       91516 :         enum_func_status ret = PASS;
    1467             :         MYSQLND_PACKET_HEADER header;
    1468       91516 :         zend_uchar * p = NULL;
    1469       91516 :         zend_bool first_iteration = TRUE;
    1470             : 
    1471       91516 :         DBG_ENTER("php_mysqlnd_read_row_ex");
    1472             : 
    1473             :         /*
    1474             :           To ease the process the server splits everything in packets up to 2^24 - 1.
    1475             :           Even in the case the payload is evenly divisible by this value, the last
    1476             :           packet will be empty, namely 0 bytes. Thus, we can read every packet and ask
    1477             :           for next one if they have 2^24 - 1 sizes. But just read the header of a
    1478             :           zero-length byte, don't read the body, there is no such.
    1479             :         */
    1480             : 
    1481       91516 :         *data_size = prealloc_more_bytes;
    1482             :         while (1) {
    1483       91516 :                 if (FAIL == mysqlnd_read_header(pfc, vio, &header, stats, error_info)) {
    1484           2 :                         ret = FAIL;
    1485           2 :                         break;
    1486             :                 }
    1487             : 
    1488       91514 :                 *data_size += header.size;
    1489             : 
    1490       91514 :                 if (first_iteration) {
    1491       91514 :                         first_iteration = FALSE;
    1492       91514 :                         *buffer = result_set_memory_pool->get_chunk(result_set_memory_pool, *data_size);
    1493       91514 :                         if (!*buffer) {
    1494           0 :                                 ret = FAIL;
    1495           0 :                                 break;
    1496             :                         }
    1497       91514 :                         p = (*buffer)->ptr;
    1498           0 :                 } else if (!first_iteration) {
    1499             :                         /* Empty packet after MYSQLND_MAX_PACKET_SIZE packet. That's ok, break */
    1500           0 :                         if (!header.size) {
    1501           0 :                                 break;
    1502             :                         }
    1503             : 
    1504             :                         /*
    1505             :                           We have to realloc the buffer.
    1506             :                         */
    1507           0 :                         if (FAIL == (*buffer)->resize_chunk((*buffer), *data_size)) {
    1508           0 :                                 SET_OOM_ERROR(error_info);
    1509           0 :                                 ret = FAIL;
    1510           0 :                                 break;
    1511             :                         }
    1512             :                         /* The position could have changed, recalculate */
    1513           0 :                         p = (*buffer)->ptr + (*data_size - header.size);
    1514             :                 }
    1515             : 
    1516       91514 :                 if (PASS != (ret = pfc->data->m.receive(pfc, vio, p, header.size, stats, error_info))) {
    1517           0 :                         DBG_ERR("Empty row packet body");
    1518           0 :                         php_error(E_WARNING, "Empty row packet body");
    1519           0 :                         break;
    1520             :                 }
    1521             : 
    1522       91514 :                 if (header.size < MYSQLND_MAX_PACKET_SIZE) {
    1523       91514 :                         break;
    1524             :                 }
    1525           0 :         }
    1526       91516 :         if (ret == FAIL && *buffer) {
    1527           0 :                 (*buffer)->free_chunk((*buffer));
    1528           0 :                 *buffer = NULL;
    1529             :         }
    1530       91516 :         *data_size -= prealloc_more_bytes;
    1531       91516 :         DBG_RETURN(ret);
    1532             : }
    1533             : /* }}} */
    1534             : 
    1535             : 
    1536             : /* {{{ php_mysqlnd_rowp_read_binary_protocol */
    1537             : enum_func_status
    1538       20106 : php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval * fields,
    1539             :                                                                           unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
    1540             :                                                                           zend_bool as_int_or_float, MYSQLND_STATS * stats)
    1541             : {
    1542             :         unsigned int i;
    1543       20106 :         const zend_uchar * p = row_buffer->ptr;
    1544             :         const zend_uchar * null_ptr;
    1545             :         zend_uchar bit;
    1546             :         zval *current_field, *end_field, *start_field;
    1547             : 
    1548       20106 :         DBG_ENTER("php_mysqlnd_rowp_read_binary_protocol");
    1549             : 
    1550       20106 :         if (!fields) {
    1551           0 :                 DBG_RETURN(FAIL);
    1552             :         }
    1553             : 
    1554       20106 :         end_field = (start_field = fields) + field_count;
    1555             : 
    1556             :         /* skip the first byte, not EODATA_MARKER -> 0x0, status */
    1557       20106 :         p++;
    1558       20106 :         null_ptr= p;
    1559       20106 :         p += (field_count + 9)/8;       /* skip null bits */
    1560       20106 :         bit     = 4;                                    /* first 2 bits are reserved */
    1561             : 
    1562       64312 :         for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) {
    1563             :                 enum_mysqlnd_collected_stats statistic;
    1564       44206 :                 const zend_uchar * orig_p = p;
    1565             : 
    1566      265236 :                 DBG_INF_FMT("Into zval=%p decoding column %u [%s.%s.%s] type=%u field->flags&unsigned=%u flags=%u is_bit=%u",
    1567             :                         current_field, i,
    1568      132618 :                         fields_metadata[i].db, fields_metadata[i].table, fields_metadata[i].name, fields_metadata[i].type,
    1569      132618 :                         fields_metadata[i].flags & UNSIGNED_FLAG, fields_metadata[i].flags, fields_metadata[i].type == MYSQL_TYPE_BIT);
    1570       44206 :                 if (*null_ptr & bit) {
    1571        1154 :                         DBG_INF("It's null");
    1572        1154 :                         ZVAL_NULL(current_field);
    1573        1154 :                         statistic = STAT_BINARY_TYPE_FETCHED_NULL;
    1574             :                 } else {
    1575       43052 :                         enum_mysqlnd_field_types type = fields_metadata[i].type;
    1576       43052 :                         mysqlnd_ps_fetch_functions[type].func(current_field, &fields_metadata[i], 0, &p);
    1577             : 
    1578       43052 :                         if (MYSQLND_G(collect_statistics)) {
    1579       43052 :                                 switch (fields_metadata[i].type) {
    1580           0 :                                         case MYSQL_TYPE_DECIMAL:        statistic = STAT_BINARY_TYPE_FETCHED_DECIMAL; break;
    1581          60 :                                         case MYSQL_TYPE_TINY:           statistic = STAT_BINARY_TYPE_FETCHED_INT8; break;
    1582          43 :                                         case MYSQL_TYPE_SHORT:          statistic = STAT_BINARY_TYPE_FETCHED_INT16; break;
    1583       19074 :                                         case MYSQL_TYPE_LONG:           statistic = STAT_BINARY_TYPE_FETCHED_INT32; break;
    1584         140 :                                         case MYSQL_TYPE_FLOAT:          statistic = STAT_BINARY_TYPE_FETCHED_FLOAT; break;
    1585          61 :                                         case MYSQL_TYPE_DOUBLE:         statistic = STAT_BINARY_TYPE_FETCHED_DOUBLE; break;
    1586           0 :                                         case MYSQL_TYPE_NULL:           statistic = STAT_BINARY_TYPE_FETCHED_NULL; break;
    1587          17 :                                         case MYSQL_TYPE_TIMESTAMP:      statistic = STAT_BINARY_TYPE_FETCHED_TIMESTAMP; break;
    1588        2050 :                                         case MYSQL_TYPE_LONGLONG:       statistic = STAT_BINARY_TYPE_FETCHED_INT64; break;
    1589          28 :                                         case MYSQL_TYPE_INT24:          statistic = STAT_BINARY_TYPE_FETCHED_INT24; break;
    1590          19 :                                         case MYSQL_TYPE_DATE:           statistic = STAT_BINARY_TYPE_FETCHED_DATE; break;
    1591          19 :                                         case MYSQL_TYPE_TIME:           statistic = STAT_BINARY_TYPE_FETCHED_TIME; break;
    1592          19 :                                         case MYSQL_TYPE_DATETIME:       statistic = STAT_BINARY_TYPE_FETCHED_DATETIME; break;
    1593          19 :                                         case MYSQL_TYPE_YEAR:           statistic = STAT_BINARY_TYPE_FETCHED_YEAR; break;
    1594           1 :                                         case MYSQL_TYPE_NEWDATE:        statistic = STAT_BINARY_TYPE_FETCHED_DATE; break;
    1595           0 :                                         case MYSQL_TYPE_VARCHAR:        statistic = STAT_BINARY_TYPE_FETCHED_STRING; break;
    1596        1487 :                                         case MYSQL_TYPE_BIT:            statistic = STAT_BINARY_TYPE_FETCHED_BIT; break;
    1597          61 :                                         case MYSQL_TYPE_NEWDECIMAL:     statistic = STAT_BINARY_TYPE_FETCHED_DECIMAL; break;
    1598           0 :                                         case MYSQL_TYPE_ENUM:           statistic = STAT_BINARY_TYPE_FETCHED_ENUM; break;
    1599           0 :                                         case MYSQL_TYPE_SET:            statistic = STAT_BINARY_TYPE_FETCHED_SET; break;
    1600           0 :                                         case MYSQL_TYPE_TINY_BLOB:      statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break;
    1601           9 :                                         case MYSQL_TYPE_MEDIUM_BLOB:statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break;
    1602           0 :                                         case MYSQL_TYPE_LONG_BLOB:      statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break;
    1603        1164 :                                         case MYSQL_TYPE_BLOB:           statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break;
    1604       18441 :                                         case MYSQL_TYPE_VAR_STRING:     statistic = STAT_BINARY_TYPE_FETCHED_STRING; break;
    1605         292 :                                         case MYSQL_TYPE_STRING:         statistic = STAT_BINARY_TYPE_FETCHED_STRING; break;
    1606          48 :                                         case MYSQL_TYPE_GEOMETRY:       statistic = STAT_BINARY_TYPE_FETCHED_GEOMETRY; break;
    1607           0 :                                         default: statistic = STAT_BINARY_TYPE_FETCHED_OTHER; break;
    1608             :                                 }
    1609             :                         }
    1610             :                 }
    1611      132618 :                 MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, statistic, 1,
    1612             :                                                                                 STAT_BYTES_RECEIVED_PURE_DATA_PS,
    1613             :                                                                                 (Z_TYPE_P(current_field) == IS_STRING)?
    1614             :                                                                                         Z_STRLEN_P(current_field) : (p - orig_p));
    1615             : 
    1616       44206 :                 if (!((bit<<=1) & 255)) {
    1617         162 :                         bit = 1;        /* to the following byte */
    1618         162 :                         null_ptr++;
    1619             :                 }
    1620             :         }
    1621             : 
    1622       20106 :         DBG_RETURN(PASS);
    1623             : }
    1624             : /* }}} */
    1625             : 
    1626             : 
    1627             : /* {{{ php_mysqlnd_rowp_read_text_protocol */
    1628             : enum_func_status
    1629       65407 : php_mysqlnd_rowp_read_text_protocol_aux(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval * fields,
    1630             :                                                                         unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
    1631             :                                                                         zend_bool as_int_or_float, MYSQLND_STATS * stats)
    1632             : {
    1633             :         unsigned int i;
    1634             :         zval *current_field, *end_field, *start_field;
    1635       65407 :         zend_uchar * p = row_buffer->ptr;
    1636       65407 :         size_t data_size = row_buffer->app;
    1637       65407 :         zend_uchar * bit_area = (zend_uchar*) row_buffer->ptr + data_size + 1; /* we allocate from here */
    1638             : 
    1639       65407 :         DBG_ENTER("php_mysqlnd_rowp_read_text_protocol_aux");
    1640             : 
    1641       65407 :         if (!fields) {
    1642           0 :                 DBG_RETURN(FAIL);
    1643             :         }
    1644             : 
    1645       65407 :         end_field = (start_field = fields) + field_count;
    1646             : 
    1647      198269 :         for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) {
    1648             :                 /* php_mysqlnd_net_field_length() call should be after *this_field_len_pos = p; */
    1649      132862 :                 const zend_ulong len = php_mysqlnd_net_field_length((const zend_uchar **) &p);
    1650             : 
    1651             :                 /* NULL or NOT NULL, this is the question! */
    1652      132862 :                 if (len == MYSQLND_NULL_LENGTH) {
    1653         691 :                         ZVAL_NULL(current_field);
    1654             :                 } else {
    1655             : #if defined(MYSQLND_STRING_TO_INT_CONVERSION)
    1656             :                         struct st_mysqlnd_perm_bind perm_bind =
    1657      132171 :                                         mysqlnd_ps_fetch_functions[fields_metadata[i].type];
    1658             : #endif
    1659      132171 :                         if (MYSQLND_G(collect_statistics)) {
    1660             :                                 enum_mysqlnd_collected_stats statistic;
    1661      132171 :                                 switch (fields_metadata[i].type) {
    1662           0 :                                         case MYSQL_TYPE_DECIMAL:        statistic = STAT_TEXT_TYPE_FETCHED_DECIMAL; break;
    1663          35 :                                         case MYSQL_TYPE_TINY:           statistic = STAT_TEXT_TYPE_FETCHED_INT8; break;
    1664          36 :                                         case MYSQL_TYPE_SHORT:          statistic = STAT_TEXT_TYPE_FETCHED_INT16; break;
    1665       64633 :                                         case MYSQL_TYPE_LONG:           statistic = STAT_TEXT_TYPE_FETCHED_INT32; break;
    1666          32 :                                         case MYSQL_TYPE_FLOAT:          statistic = STAT_TEXT_TYPE_FETCHED_FLOAT; break;
    1667          32 :                                         case MYSQL_TYPE_DOUBLE:         statistic = STAT_TEXT_TYPE_FETCHED_DOUBLE; break;
    1668           0 :                                         case MYSQL_TYPE_NULL:           statistic = STAT_TEXT_TYPE_FETCHED_NULL; break;
    1669          40 :                                         case MYSQL_TYPE_TIMESTAMP:      statistic = STAT_TEXT_TYPE_FETCHED_TIMESTAMP; break;
    1670        1286 :                                         case MYSQL_TYPE_LONGLONG:       statistic = STAT_TEXT_TYPE_FETCHED_INT64; break;
    1671          23 :                                         case MYSQL_TYPE_INT24:          statistic = STAT_TEXT_TYPE_FETCHED_INT24; break;
    1672          13 :                                         case MYSQL_TYPE_DATE:           statistic = STAT_TEXT_TYPE_FETCHED_DATE; break;
    1673          13 :                                         case MYSQL_TYPE_TIME:           statistic = STAT_TEXT_TYPE_FETCHED_TIME; break;
    1674          15 :                                         case MYSQL_TYPE_DATETIME:       statistic = STAT_TEXT_TYPE_FETCHED_DATETIME; break;
    1675          13 :                                         case MYSQL_TYPE_YEAR:           statistic = STAT_TEXT_TYPE_FETCHED_YEAR; break;
    1676           1 :                                         case MYSQL_TYPE_NEWDATE:        statistic = STAT_TEXT_TYPE_FETCHED_DATE; break;
    1677           0 :                                         case MYSQL_TYPE_VARCHAR:        statistic = STAT_TEXT_TYPE_FETCHED_STRING; break;
    1678         463 :                                         case MYSQL_TYPE_BIT:            statistic = STAT_TEXT_TYPE_FETCHED_BIT; break;
    1679          32 :                                         case MYSQL_TYPE_NEWDECIMAL:     statistic = STAT_TEXT_TYPE_FETCHED_DECIMAL; break;
    1680           0 :                                         case MYSQL_TYPE_ENUM:           statistic = STAT_TEXT_TYPE_FETCHED_ENUM; break;
    1681           0 :                                         case MYSQL_TYPE_SET:            statistic = STAT_TEXT_TYPE_FETCHED_SET; break;
    1682           0 :                                         case MYSQL_TYPE_JSON:           statistic = STAT_TEXT_TYPE_FETCHED_JSON; break;
    1683           0 :                                         case MYSQL_TYPE_TINY_BLOB:      statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
    1684          16 :                                         case MYSQL_TYPE_MEDIUM_BLOB:statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
    1685           0 :                                         case MYSQL_TYPE_LONG_BLOB:      statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
    1686         164 :                                         case MYSQL_TYPE_BLOB:           statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
    1687       18184 :                                         case MYSQL_TYPE_VAR_STRING:     statistic = STAT_TEXT_TYPE_FETCHED_STRING; break;
    1688       47092 :                                         case MYSQL_TYPE_STRING:         statistic = STAT_TEXT_TYPE_FETCHED_STRING; break;
    1689          48 :                                         case MYSQL_TYPE_GEOMETRY:       statistic = STAT_TEXT_TYPE_FETCHED_GEOMETRY; break;
    1690           0 :                                         default: statistic = STAT_TEXT_TYPE_FETCHED_OTHER; break;
    1691             :                                 }
    1692      132171 :                                 MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, statistic, 1, STAT_BYTES_RECEIVED_PURE_DATA_TEXT, len);
    1693             :                         }
    1694             : #ifdef MYSQLND_STRING_TO_INT_CONVERSION
    1695      132179 :                         if (as_int_or_float && perm_bind.php_type == IS_LONG) {
    1696           8 :                                 zend_uchar save = *(p + len);
    1697             :                                 /* We have to make it ASCIIZ temporarily */
    1698           8 :                                 *(p + len) = '\0';
    1699           8 :                                 if (perm_bind.pack_len < SIZEOF_ZEND_LONG) {
    1700             :                                         /* direct conversion */
    1701             :                                         int64_t v =
    1702             : #ifndef PHP_WIN32
    1703           6 :                                                 atoll((char *) p);
    1704             : #else
    1705             :                                                 _atoi64((char *) p);
    1706             : #endif
    1707           6 :                                         ZVAL_LONG(current_field, (zend_long) v); /* the cast is safe */
    1708             :                                 } else {
    1709             :                                         uint64_t v =
    1710             : #ifndef PHP_WIN32
    1711           2 :                                                 (uint64_t) atoll((char *) p);
    1712             : #else
    1713             :                                                 (uint64_t) _atoi64((char *) p);
    1714             : #endif
    1715           2 :                                         zend_bool uns = fields_metadata[i].flags & UNSIGNED_FLAG? TRUE:FALSE;
    1716             :                                         /* We have to make it ASCIIZ temporarily */
    1717             : #if SIZEOF_ZEND_LONG==8
    1718           2 :                                         if (uns == TRUE && v > 9223372036854775807L)
    1719             : #elif SIZEOF_ZEND_LONG==4
    1720             :                                         if ((uns == TRUE && v > L64(2147483647)) ||
    1721             :                                                 (uns == FALSE && (( L64(2147483647) < (int64_t) v) ||
    1722             :                                                 (L64(-2147483648) > (int64_t) v))))
    1723             : #else
    1724             : #error Need fix for this architecture
    1725             : #endif /* SIZEOF */
    1726             :                                         {
    1727           0 :                                                 ZVAL_STRINGL(current_field, (char *)p, len);
    1728             :                                         } else {
    1729           2 :                                                 ZVAL_LONG(current_field, (zend_long) v); /* the cast is safe */
    1730             :                                         }
    1731             :                                 }
    1732           8 :                                 *(p + len) = save;
    1733      132165 :                         } else if (as_int_or_float && perm_bind.php_type == IS_DOUBLE) {
    1734           2 :                                 zend_uchar save = *(p + len);
    1735             :                                 /* We have to make it ASCIIZ temporarily */
    1736           2 :                                 *(p + len) = '\0';
    1737           2 :                                 ZVAL_DOUBLE(current_field, atof((char *) p));
    1738           2 :                                 *(p + len) = save;
    1739             :                         } else
    1740             : #endif /* MYSQLND_STRING_TO_INT_CONVERSION */
    1741      132161 :                         if (fields_metadata[i].type == MYSQL_TYPE_BIT) {
    1742             :                                 /*
    1743             :                                   BIT fields are specially handled. As they come as bit mask, we have
    1744             :                                   to convert it to human-readable representation. As the bits take
    1745             :                                   less space in the protocol than the numbers they represent, we don't
    1746             :                                   have enough space in the packet buffer to overwrite inside.
    1747             :                                   Thus, a bit more space is pre-allocated at the end of the buffer,
    1748             :                                   see php_mysqlnd_rowp_read(). And we add the strings at the end.
    1749             :                                   Definitely not nice, _hackish_ :(, but works.
    1750             :                                 */
    1751         462 :                                 zend_uchar *start = bit_area;
    1752         462 :                                 ps_fetch_from_1_to_8_bytes(current_field, &(fields_metadata[i]), 0, (const zend_uchar **) &p, len);
    1753             :                                 /*
    1754             :                                   We have advanced in ps_fetch_from_1_to_8_bytes. We should go back because
    1755             :                                   later in this function there will be an advancement.
    1756             :                                 */
    1757         462 :                                 p -= len;
    1758         462 :                                 if (Z_TYPE_P(current_field) == IS_LONG) {
    1759         462 :                                         bit_area += 1 + sprintf((char *)start, ZEND_LONG_FMT, Z_LVAL_P(current_field));
    1760         924 :                                         ZVAL_STRINGL(current_field, (char *) start, bit_area - start - 1);
    1761           0 :                                 } else if (Z_TYPE_P(current_field) == IS_STRING){
    1762           0 :                                         memcpy(bit_area, Z_STRVAL_P(current_field), Z_STRLEN_P(current_field));
    1763           0 :                                         bit_area += Z_STRLEN_P(current_field);
    1764           0 :                                         *bit_area++ = '\0';
    1765             :                                         zval_dtor(current_field);
    1766           0 :                                         ZVAL_STRINGL(current_field, (char *) start, bit_area - start - 1);
    1767             :                                 }
    1768             :                         } else {
    1769      263398 :                                 ZVAL_STRINGL(current_field, (char *)p, len);
    1770             :                         }
    1771      132171 :                         p += len;
    1772             :                 }
    1773             :         }
    1774             : 
    1775       65407 :         DBG_RETURN(PASS);
    1776             : }
    1777             : /* }}} */
    1778             : 
    1779             : 
    1780             : /* {{{ php_mysqlnd_rowp_read_text_protocol_zval */
    1781             : enum_func_status
    1782       65356 : php_mysqlnd_rowp_read_text_protocol_zval(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval * fields,
    1783             :                                                                         unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
    1784             :                                                                         zend_bool as_int_or_float, MYSQLND_STATS * stats)
    1785             : {
    1786             :         enum_func_status ret;
    1787       65356 :         DBG_ENTER("php_mysqlnd_rowp_read_text_protocol_zval");
    1788       65356 :         ret = php_mysqlnd_rowp_read_text_protocol_aux(row_buffer, fields, field_count, fields_metadata, as_int_or_float, stats);
    1789       65356 :         DBG_RETURN(ret);
    1790             : }
    1791             : /* }}} */
    1792             : 
    1793             : 
    1794             : /* {{{ php_mysqlnd_rowp_read_text_protocol_c */
    1795             : enum_func_status
    1796          51 : php_mysqlnd_rowp_read_text_protocol_c(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval * fields,
    1797             :                                                                         unsigned int field_count, const MYSQLND_FIELD * fields_metadata,
    1798             :                                                                         zend_bool as_int_or_float, MYSQLND_STATS * stats)
    1799             : {
    1800             :         enum_func_status ret;
    1801          51 :         DBG_ENTER("php_mysqlnd_rowp_read_text_protocol_c");
    1802          51 :         ret = php_mysqlnd_rowp_read_text_protocol_aux(row_buffer, fields, field_count, fields_metadata, as_int_or_float, stats);
    1803          51 :         DBG_RETURN(ret);
    1804             : }
    1805             : /* }}} */
    1806             : 
    1807             : 
    1808             : /* {{{ php_mysqlnd_rowp_read */
    1809             : /*
    1810             :   if normal statements => packet->fields is created by this function,
    1811             :   if PS => packet->fields is passed from outside
    1812             : */
    1813             : static enum_func_status
    1814       91516 : php_mysqlnd_rowp_read(void * _packet)
    1815             : {
    1816       91516 :         MYSQLND_PACKET_ROW *packet= (MYSQLND_PACKET_ROW *) _packet;
    1817       91516 :         MYSQLND_ERROR_INFO * error_info = packet->header.error_info;
    1818       91516 :         MYSQLND_PFC * pfc = packet->header.protocol_frame_codec;
    1819       91516 :         MYSQLND_VIO * vio = packet->header.vio;
    1820       91516 :         MYSQLND_STATS * stats = packet->header.stats;
    1821             :         zend_uchar *p;
    1822       91516 :         enum_func_status ret = PASS;
    1823       91516 :         size_t post_alloc_for_bit_fields = 0;
    1824       91516 :         size_t data_size = 0;
    1825             : 
    1826       91516 :         DBG_ENTER("php_mysqlnd_rowp_read");
    1827             : 
    1828       91516 :         if (!packet->binary_protocol && packet->bit_fields_count) {
    1829             :                 /* For every field we need terminating \0 */
    1830         976 :                 post_alloc_for_bit_fields = packet->bit_fields_total_len + packet->bit_fields_count;
    1831             :         }
    1832             : 
    1833      274548 :         ret = php_mysqlnd_read_row_ex(pfc, vio, stats, error_info,
    1834       91516 :                                                                   packet->result_set_memory_pool, &packet->row_buffer, &data_size,
    1835       91516 :                                                                   packet->persistent_alloc, post_alloc_for_bit_fields
    1836             :                                                                  );
    1837       91516 :         if (FAIL == ret) {
    1838           2 :                 goto end;
    1839             :         }
    1840       91514 :         MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, packet_type_to_statistic_byte_count[PROT_ROW_PACKET],
    1841             :                                                                                 MYSQLND_HEADER_SIZE + packet->header.size,
    1842             :                                                                                 packet_type_to_statistic_packet_count[PROT_ROW_PACKET],
    1843             :                                                                                 1);
    1844             : 
    1845             :         /* packet->row_buffer->ptr is of size 'data_size + 1' */
    1846       91514 :         packet->header.size = data_size;
    1847       91514 :         packet->row_buffer->app = data_size;
    1848             : 
    1849       91514 :         if (ERROR_MARKER == (*(p = packet->row_buffer->ptr))) {
    1850             :                 /*
    1851             :                    Error message as part of the result set,
    1852             :                    not good but we should not hang. See:
    1853             :                    Bug #27876 : SF with cyrillic variable name fails during execution
    1854             :                 */
    1855           0 :                 ret = FAIL;
    1856           0 :                 php_mysqlnd_read_error_from_line(p + 1, data_size - 1,
    1857             :                                                                                  packet->error_info.error,
    1858             :                                                                                  sizeof(packet->error_info.error),
    1859             :                                                                                  &packet->error_info.error_no,
    1860             :                                                                                  packet->error_info.sqlstate
    1861             :                                                                                 );
    1862       95965 :         } else if (EODATA_MARKER == *p && data_size < 8) { /* EOF */
    1863        4451 :                 packet->eof = TRUE;
    1864        4451 :                 p++;
    1865        4451 :                 if (data_size > 1) {
    1866        4451 :                         packet->warning_count = uint2korr(p);
    1867        4451 :                         p += 2;
    1868        4451 :                         packet->server_status = uint2korr(p);
    1869             :                         /* Seems we have 3 bytes reserved for future use */
    1870        4451 :                         DBG_INF_FMT("server_status=%u warning_count=%u", packet->server_status, packet->warning_count);
    1871             :                 }
    1872             :         } else {
    1873       87063 :                 MYSQLND_INC_CONN_STATISTIC(stats,
    1874             :                                                                         packet->binary_protocol? STAT_ROWS_FETCHED_FROM_SERVER_PS:
    1875             :                                                                                                                          STAT_ROWS_FETCHED_FROM_SERVER_NORMAL);
    1876             : 
    1877       87063 :                 packet->eof = FALSE;
    1878             :                 /* packet->field_count is set by the user of the packet */
    1879             : 
    1880       87063 :                 if (!packet->skip_extraction) {
    1881       17704 :                         if (!packet->fields) {
    1882       17704 :                                 DBG_INF("Allocating packet->fields");
    1883             :                                 /*
    1884             :                                   old-API will probably set packet->fields to NULL every time, though for
    1885             :                                   unbuffered sets it makes not much sense as the zvals in this buffer matter,
    1886             :                                   not the buffer. Constantly allocating and deallocating brings nothing.
    1887             : 
    1888             :                                   For PS - if stmt_store() is performed, thus we don't have a cursor, it will
    1889             :                                   behave just like old-API buffered. Cursors will behave like a bit different,
    1890             :                                   but mostly like old-API unbuffered and thus will populate this array with
    1891             :                                   value.
    1892             :                                 */
    1893       17704 :                                 packet->fields = mnd_pecalloc(packet->field_count, sizeof(zval),
    1894             :                                                                                                                 packet->persistent_alloc);
    1895             :                         }
    1896             :                 } else {
    1897       69359 :                         MYSQLND_INC_CONN_STATISTIC(stats,
    1898             :                                                                                 packet->binary_protocol? STAT_ROWS_SKIPPED_PS:
    1899             :                                                                                                                                  STAT_ROWS_SKIPPED_NORMAL);
    1900             :                 }
    1901             :         }
    1902             : 
    1903             : end:
    1904       91516 :         DBG_RETURN(ret);
    1905             : }
    1906             : /* }}} */
    1907             : 
    1908             : 
    1909             : /* {{{ php_mysqlnd_rowp_free_mem */
    1910             : static void
    1911        4432 : php_mysqlnd_rowp_free_mem(void * _packet, zend_bool stack_allocation)
    1912             : {
    1913             :         MYSQLND_PACKET_ROW *p;
    1914             : 
    1915        4432 :         DBG_ENTER("php_mysqlnd_rowp_free_mem");
    1916        4432 :         p = (MYSQLND_PACKET_ROW *) _packet;
    1917        4432 :         if (p->row_buffer) {
    1918        4423 :                 p->row_buffer->free_chunk(p->row_buffer);
    1919        4423 :                 p->row_buffer = NULL;
    1920             :         }
    1921        4432 :         DBG_INF_FMT("stack_allocation=%u persistent=%u", (int)stack_allocation, (int)p->header.persistent);
    1922             :         /*
    1923             :           Don't free packet->fields :
    1924             :           - normal queries -> store_result() | fetch_row_unbuffered() will transfer
    1925             :             the ownership and NULL it.
    1926             :           - PS will pass in it the bound variables, we have to use them! and of course
    1927             :             not free the array. As it is passed to us, we should not clean it ourselves.
    1928             :         */
    1929        4432 :         if (!stack_allocation) {
    1930        4432 :                 mnd_pefree(p, p->header.persistent);
    1931             :         }
    1932        4432 :         DBG_VOID_RETURN;
    1933             : }
    1934             : /* }}} */
    1935             : 
    1936             : 
    1937             : /* {{{ php_mysqlnd_stats_read */
    1938             : static enum_func_status
    1939          15 : php_mysqlnd_stats_read(void * _packet)
    1940             : {
    1941          15 :         MYSQLND_PACKET_STATS *packet= (MYSQLND_PACKET_STATS *) _packet;
    1942          15 :         MYSQLND_ERROR_INFO * error_info = packet->header.error_info;
    1943          15 :         MYSQLND_PFC * pfc = packet->header.protocol_frame_codec;
    1944          15 :         MYSQLND_VIO * vio = packet->header.vio;
    1945          15 :         MYSQLND_STATS * stats = packet->header.stats;
    1946          15 :         MYSQLND_CONNECTION_STATE * connection_state = packet->header.connection_state;
    1947          15 :         size_t buf_len = pfc->cmd_buffer.length;
    1948          15 :         zend_uchar *buf = (zend_uchar *) pfc->cmd_buffer.buffer;
    1949             : 
    1950          15 :         DBG_ENTER("php_mysqlnd_stats_read");
    1951             : 
    1952          15 :         if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, buf_len, "statistics", PROT_STATS_PACKET)) {
    1953           0 :                 DBG_RETURN(FAIL);
    1954             :         }
    1955             : 
    1956          15 :         packet->message.s = mnd_emalloc(packet->header.size + 1);
    1957          15 :         memcpy(packet->message.s, buf, packet->header.size);
    1958          15 :         packet->message.s[packet->header.size] = '\0';
    1959          15 :         packet->message.l = packet->header.size;
    1960             : 
    1961          15 :         DBG_RETURN(PASS);
    1962             : }
    1963             : /* }}} */
    1964             : 
    1965             : 
    1966             : /* {{{ php_mysqlnd_stats_free_mem */
    1967             : static
    1968          15 : void php_mysqlnd_stats_free_mem(void * _packet, zend_bool stack_allocation)
    1969             : {
    1970          15 :         MYSQLND_PACKET_STATS *p= (MYSQLND_PACKET_STATS *) _packet;
    1971          15 :         if (p->message.s) {
    1972          15 :                 mnd_efree(p->message.s);
    1973          15 :                 p->message.s = NULL;
    1974             :         }
    1975          15 :         if (!stack_allocation) {
    1976          15 :                 mnd_pefree(p, p->header.persistent);
    1977             :         }
    1978          15 : }
    1979             : /* }}} */
    1980             : 
    1981             : 
    1982             : /* 1 + 4 (id) + 2 (field_c) + 2 (param_c) + 1 (filler) + 2 (warnings ) */
    1983             : #define PREPARE_RESPONSE_SIZE_41 9
    1984             : #define PREPARE_RESPONSE_SIZE_50 12
    1985             : 
    1986             : /* {{{ php_mysqlnd_prepare_read */
    1987             : static enum_func_status
    1988        4250 : php_mysqlnd_prepare_read(void * _packet)
    1989             : {
    1990        4250 :         MYSQLND_PACKET_PREPARE_RESPONSE *packet= (MYSQLND_PACKET_PREPARE_RESPONSE *) _packet;
    1991        4250 :         MYSQLND_ERROR_INFO * error_info = packet->header.error_info;
    1992        4250 :         MYSQLND_PFC * pfc = packet->header.protocol_frame_codec;
    1993        4250 :         MYSQLND_VIO * vio = packet->header.vio;
    1994        4250 :         MYSQLND_STATS * stats = packet->header.stats;
    1995        4250 :         MYSQLND_CONNECTION_STATE * connection_state = packet->header.connection_state;
    1996             :         /* In case of an error, we should have place to put it */
    1997        4250 :         size_t buf_len = pfc->cmd_buffer.length;
    1998        4250 :         zend_uchar *buf = (zend_uchar *) pfc->cmd_buffer.buffer;
    1999        4250 :         zend_uchar *p = buf;
    2000        4250 :         const zend_uchar * const begin = buf;
    2001             :         unsigned int data_size;
    2002             : 
    2003        4250 :         DBG_ENTER("php_mysqlnd_prepare_read");
    2004             : 
    2005        4250 :         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)) {
    2006           1 :                 DBG_RETURN(FAIL);
    2007             :         }
    2008        4249 :         BAIL_IF_NO_MORE_DATA;
    2009             : 
    2010        4249 :         data_size = packet->header.size;
    2011        4249 :         packet->error_code = uint1korr(p);
    2012        4249 :         p++;
    2013        4249 :         BAIL_IF_NO_MORE_DATA;
    2014             : 
    2015        4249 :         if (ERROR_MARKER == packet->error_code) {
    2016          26 :                 php_mysqlnd_read_error_from_line(p, data_size - 1,
    2017             :                                                                                  packet->error_info.error,
    2018             :                                                                                  sizeof(packet->error_info.error),
    2019             :                                                                                  &packet->error_info.error_no,
    2020             :                                                                                  packet->error_info.sqlstate
    2021             :                                                                                 );
    2022          26 :                 DBG_RETURN(PASS);
    2023             :         }
    2024             : 
    2025        4223 :         if (data_size != PREPARE_RESPONSE_SIZE_41 &&
    2026             :                 data_size != PREPARE_RESPONSE_SIZE_50 &&
    2027             :                 !(data_size > PREPARE_RESPONSE_SIZE_50)) {
    2028           0 :                 DBG_ERR_FMT("Wrong COM_STMT_PREPARE response size. Received %u", data_size);
    2029           0 :                 php_error(E_WARNING, "Wrong COM_STMT_PREPARE response size. Received %u", data_size);
    2030           0 :                 DBG_RETURN(FAIL);
    2031             :         }
    2032             : 
    2033        4223 :         packet->stmt_id = uint4korr(p);
    2034        4223 :         p += 4;
    2035        4223 :         BAIL_IF_NO_MORE_DATA;
    2036             : 
    2037             :         /* Number of columns in result set */
    2038        4223 :         packet->field_count = uint2korr(p);
    2039        4223 :         p += 2;
    2040        4223 :         BAIL_IF_NO_MORE_DATA;
    2041             : 
    2042        4223 :         packet->param_count = uint2korr(p);
    2043        4223 :         p += 2;
    2044        4223 :         BAIL_IF_NO_MORE_DATA;
    2045             : 
    2046        4223 :         if (data_size > 9) {
    2047             :                 /* 0x0 filler sent by the server for 5.0+ clients */
    2048        4223 :                 p++;
    2049        4223 :                 BAIL_IF_NO_MORE_DATA;
    2050             : 
    2051        4223 :                 packet->warning_count = uint2korr(p);
    2052             :         }
    2053             : 
    2054        4223 :         DBG_INF_FMT("Prepare packet read: stmt_id=%u fields=%u params=%u",
    2055             :                                 packet->stmt_id, packet->field_count, packet->param_count);
    2056             : 
    2057        4223 :         BAIL_IF_NO_MORE_DATA;
    2058             : 
    2059        4223 :         DBG_RETURN(PASS);
    2060             : premature_end:
    2061           0 :         DBG_ERR_FMT("PREPARE packet %d bytes shorter than expected", p - begin - packet->header.size);
    2062           0 :         php_error_docref(NULL, E_WARNING, "PREPARE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
    2063           0 :                                          p - begin - packet->header.size);
    2064           0 :         DBG_RETURN(FAIL);
    2065             : }
    2066             : /* }}} */
    2067             : 
    2068             : 
    2069             : /* {{{ php_mysqlnd_prepare_free_mem */
    2070             : static void
    2071        4250 : php_mysqlnd_prepare_free_mem(void * _packet, zend_bool stack_allocation)
    2072             : {
    2073        4250 :         MYSQLND_PACKET_PREPARE_RESPONSE *p= (MYSQLND_PACKET_PREPARE_RESPONSE *) _packet;
    2074        4250 :         if (!stack_allocation) {
    2075        4250 :                 mnd_pefree(p, p->header.persistent);
    2076             :         }
    2077        4250 : }
    2078             : /* }}} */
    2079             : 
    2080             : 
    2081             : /* {{{ php_mysqlnd_chg_user_read */
    2082             : static enum_func_status
    2083          74 : php_mysqlnd_chg_user_read(void * _packet)
    2084             : {
    2085          74 :         MYSQLND_PACKET_CHG_USER_RESPONSE *packet= (MYSQLND_PACKET_CHG_USER_RESPONSE *) _packet;
    2086          74 :         MYSQLND_ERROR_INFO * error_info = packet->header.error_info;
    2087          74 :         MYSQLND_PFC * pfc = packet->header.protocol_frame_codec;
    2088          74 :         MYSQLND_VIO * vio = packet->header.vio;
    2089          74 :         MYSQLND_STATS * stats = packet->header.stats;
    2090          74 :         MYSQLND_CONNECTION_STATE * connection_state = packet->header.connection_state;
    2091             :         /* There could be an error message */
    2092          74 :         size_t buf_len = pfc->cmd_buffer.length;
    2093          74 :         zend_uchar *buf = (zend_uchar *) pfc->cmd_buffer.buffer;
    2094          74 :         zend_uchar *p = buf;
    2095          74 :         const zend_uchar * const begin = buf;
    2096             : 
    2097          74 :         DBG_ENTER("php_mysqlnd_chg_user_read");
    2098             : 
    2099          74 :         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)) {
    2100           0 :                 DBG_RETURN(FAIL);
    2101             :         }
    2102          74 :         BAIL_IF_NO_MORE_DATA;
    2103             : 
    2104             :         /*
    2105             :           Don't increment. First byte is ERROR_MARKER on error, but otherwise is starting byte
    2106             :           of encoded sequence for length.
    2107             :         */
    2108             : 
    2109             :         /* Should be always 0x0 or ERROR_MARKER for error */
    2110          74 :         packet->response_code = uint1korr(p);
    2111          74 :         p++;
    2112             : 
    2113          74 :         if (packet->header.size == 1 && buf[0] == EODATA_MARKER && packet->server_capabilities & CLIENT_SECURE_CONNECTION) {
    2114             :                 /* We don't handle 3.23 authentication */
    2115           0 :                 packet->server_asked_323_auth = TRUE;
    2116           0 :                 DBG_RETURN(FAIL);
    2117             :         }
    2118             : 
    2119          74 :         if (ERROR_MARKER == packet->response_code) {
    2120          14 :                 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
    2121             :                                                                                  packet->error_info.error,
    2122             :                                                                                  sizeof(packet->error_info.error),
    2123             :                                                                                  &packet->error_info.error_no,
    2124             :                                                                                  packet->error_info.sqlstate
    2125             :                                                                                 );
    2126             :         }
    2127          74 :         BAIL_IF_NO_MORE_DATA;
    2128          74 :         if (packet->response_code == 0xFE && packet->header.size > (size_t) (p - buf)) {
    2129           0 :                 packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE);
    2130           0 :                 packet->new_auth_protocol_len = strlen(packet->new_auth_protocol);
    2131           0 :                 p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */
    2132           0 :                 packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf);
    2133           0 :                 if (packet->new_auth_protocol_data_len) {
    2134           0 :                         packet->new_auth_protocol_data = mnd_emalloc(packet->new_auth_protocol_data_len);
    2135           0 :                         memcpy(packet->new_auth_protocol_data, p, packet->new_auth_protocol_data_len);
    2136             :                 }
    2137           0 :                 DBG_INF_FMT("The server requested switching auth plugin to : %s", packet->new_auth_protocol);
    2138           0 :                 DBG_INF_FMT("Server salt : [%*s]", packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
    2139             :         }
    2140             : 
    2141          74 :         DBG_RETURN(PASS);
    2142             : premature_end:
    2143           0 :         DBG_ERR_FMT("CHANGE_USER packet %d bytes shorter than expected", p - begin - packet->header.size);
    2144           0 :         php_error_docref(NULL, E_WARNING, "CHANGE_USER packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
    2145           0 :                                                  p - begin - packet->header.size);
    2146           0 :         DBG_RETURN(FAIL);
    2147             : }
    2148             : /* }}} */
    2149             : 
    2150             : 
    2151             : /* {{{ php_mysqlnd_chg_user_free_mem */
    2152             : static void
    2153          75 : php_mysqlnd_chg_user_free_mem(void * _packet, zend_bool stack_allocation)
    2154             : {
    2155          75 :         MYSQLND_PACKET_CHG_USER_RESPONSE * p = (MYSQLND_PACKET_CHG_USER_RESPONSE *) _packet;
    2156             : 
    2157          75 :         if (p->new_auth_protocol) {
    2158           0 :                 mnd_efree(p->new_auth_protocol);
    2159           0 :                 p->new_auth_protocol = NULL;
    2160             :         }
    2161          75 :         p->new_auth_protocol_len = 0;
    2162             : 
    2163          75 :         if (p->new_auth_protocol_data) {
    2164           0 :                 mnd_efree(p->new_auth_protocol_data);
    2165           0 :                 p->new_auth_protocol_data = NULL;
    2166             :         }
    2167          75 :         p->new_auth_protocol_data_len = 0;
    2168             : 
    2169          75 :         if (!stack_allocation) {
    2170          75 :                 mnd_pefree(p, p->header.persistent);
    2171             :         }
    2172          75 : }
    2173             : /* }}} */
    2174             : 
    2175             : 
    2176             : /* {{{ php_mysqlnd_sha256_pk_request_write */
    2177             : static
    2178           0 : size_t php_mysqlnd_sha256_pk_request_write(void * _packet)
    2179             : {
    2180           0 :         MYSQLND_PACKET_SHA256_PK_REQUEST * packet = (MYSQLND_PACKET_SHA256_PK_REQUEST *) _packet;
    2181           0 :         MYSQLND_ERROR_INFO * error_info = packet->header.error_info;
    2182           0 :         MYSQLND_PFC * pfc = packet->header.protocol_frame_codec;
    2183           0 :         MYSQLND_VIO * vio = packet->header.vio;
    2184           0 :         MYSQLND_STATS * stats = packet->header.stats;
    2185             :         zend_uchar buffer[MYSQLND_HEADER_SIZE + 1];
    2186             :         size_t sent;
    2187             : 
    2188           0 :         DBG_ENTER("php_mysqlnd_sha256_pk_request_write");
    2189             : 
    2190           0 :         int1store(buffer + MYSQLND_HEADER_SIZE, '\1');
    2191           0 :         sent = pfc->data->m.send(pfc, vio, buffer, 1, stats, error_info);
    2192             : 
    2193           0 :         DBG_RETURN(sent);
    2194             : }
    2195             : /* }}} */
    2196             : 
    2197             : 
    2198             : /* {{{ php_mysqlnd_sha256_pk_request_free_mem */
    2199             : static
    2200           0 : void php_mysqlnd_sha256_pk_request_free_mem(void * _packet, zend_bool stack_allocation)
    2201             : {
    2202           0 :         if (!stack_allocation) {
    2203           0 :                 MYSQLND_PACKET_SHA256_PK_REQUEST * p = (MYSQLND_PACKET_SHA256_PK_REQUEST *) _packet;
    2204           0 :                 mnd_pefree(p, p->header.persistent);
    2205             :         }
    2206           0 : }
    2207             : /* }}} */
    2208             : 
    2209             : 
    2210             : #define SHA256_PK_REQUEST_RESP_BUFFER_SIZE 2048
    2211             : 
    2212             : /* {{{ php_mysqlnd_sha256_pk_request_response_read */
    2213             : static enum_func_status
    2214           0 : php_mysqlnd_sha256_pk_request_response_read(void * _packet)
    2215             : {
    2216           0 :         MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE * packet= (MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE *) _packet;
    2217           0 :         MYSQLND_ERROR_INFO * error_info = packet->header.error_info;
    2218           0 :         MYSQLND_PFC * pfc = packet->header.protocol_frame_codec;
    2219           0 :         MYSQLND_VIO * vio = packet->header.vio;
    2220           0 :         MYSQLND_STATS * stats = packet->header.stats;
    2221           0 :         MYSQLND_CONNECTION_STATE * connection_state = packet->header.connection_state;
    2222             :         zend_uchar buf[SHA256_PK_REQUEST_RESP_BUFFER_SIZE];
    2223           0 :         zend_uchar *p = buf;
    2224           0 :         const zend_uchar * const begin = buf;
    2225             : 
    2226           0 :         DBG_ENTER("php_mysqlnd_sha256_pk_request_response_read");
    2227             : 
    2228             :         /* leave space for terminating safety \0 */
    2229           0 :         if (FAIL == mysqlnd_read_packet_header_and_body(&(packet->header), pfc, vio, stats, error_info, connection_state, buf, sizeof(buf), "SHA256_PK_REQUEST_RESPONSE", PROT_SHA256_PK_REQUEST_RESPONSE_PACKET)) {
    2230           0 :                 DBG_RETURN(FAIL);
    2231             :         }
    2232           0 :         BAIL_IF_NO_MORE_DATA;
    2233             : 
    2234           0 :         p++;
    2235           0 :         BAIL_IF_NO_MORE_DATA;
    2236             : 
    2237           0 :         packet->public_key_len = packet->header.size - (p - buf);
    2238           0 :         packet->public_key = mnd_emalloc(packet->public_key_len + 1);
    2239           0 :         memcpy(packet->public_key, p, packet->public_key_len);
    2240           0 :         packet->public_key[packet->public_key_len] = '\0';
    2241             : 
    2242           0 :         DBG_RETURN(PASS);
    2243             : 
    2244             : premature_end:
    2245           0 :         DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size);
    2246           0 :         php_error_docref(NULL, E_WARNING, "SHA256_PK_REQUEST_RESPONSE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
    2247           0 :                                          p - begin - packet->header.size);
    2248           0 :         DBG_RETURN(FAIL);
    2249             : }
    2250             : /* }}} */
    2251             : 
    2252             : 
    2253             : /* {{{ php_mysqlnd_sha256_pk_request_response_free_mem */
    2254             : static void
    2255           0 : php_mysqlnd_sha256_pk_request_response_free_mem(void * _packet, zend_bool stack_allocation)
    2256             : {
    2257           0 :         MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE * p = (MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE *) _packet;
    2258           0 :         if (p->public_key) {
    2259           0 :                 mnd_efree(p->public_key);
    2260           0 :                 p->public_key = NULL;
    2261             :         }
    2262           0 :         p->public_key_len = 0;
    2263             : 
    2264           0 :         if (!stack_allocation) {
    2265           0 :                 mnd_pefree(p, p->header.persistent);
    2266             :         }
    2267           0 : }
    2268             : /* }}} */
    2269             : 
    2270             : 
    2271             : /* {{{ packet_methods */
    2272             : static
    2273             : mysqlnd_packet_methods packet_methods[PROT_LAST] =
    2274             : {
    2275             :         {
    2276             :                 sizeof(MYSQLND_PACKET_GREET),
    2277             :                 php_mysqlnd_greet_read,
    2278             :                 NULL, /* write */
    2279             :                 php_mysqlnd_greet_free_mem,
    2280             :         }, /* PROT_GREET_PACKET */
    2281             :         {
    2282             :                 sizeof(MYSQLND_PACKET_AUTH),
    2283             :                 NULL, /* read */
    2284             :                 php_mysqlnd_auth_write,
    2285             :                 php_mysqlnd_auth_free_mem,
    2286             :         }, /* PROT_AUTH_PACKET */
    2287             :         {
    2288             :                 sizeof(MYSQLND_PACKET_AUTH_RESPONSE),
    2289             :                 php_mysqlnd_auth_response_read, /* read */
    2290             :                 NULL, /* write */
    2291             :                 php_mysqlnd_auth_response_free_mem,
    2292             :         }, /* PROT_AUTH_RESP_PACKET */
    2293             :         {
    2294             :                 sizeof(MYSQLND_PACKET_CHANGE_AUTH_RESPONSE),
    2295             :                 NULL, /* read */
    2296             :                 php_mysqlnd_change_auth_response_write, /* write */
    2297             :                 php_mysqlnd_change_auth_response_free_mem,
    2298             :         }, /* PROT_CHANGE_AUTH_RESP_PACKET */
    2299             :         {
    2300             :                 sizeof(MYSQLND_PACKET_OK),
    2301             :                 php_mysqlnd_ok_read, /* read */
    2302             :                 NULL, /* write */
    2303             :                 php_mysqlnd_ok_free_mem,
    2304             :         }, /* PROT_OK_PACKET */
    2305             :         {
    2306             :                 sizeof(MYSQLND_PACKET_EOF),
    2307             :                 php_mysqlnd_eof_read, /* read */
    2308             :                 NULL, /* write */
    2309             :                 php_mysqlnd_eof_free_mem,
    2310             :         }, /* PROT_EOF_PACKET */
    2311             :         {
    2312             :                 sizeof(MYSQLND_PACKET_COMMAND),
    2313             :                 NULL, /* read */
    2314             :                 php_mysqlnd_cmd_write, /* write */
    2315             :                 php_mysqlnd_cmd_free_mem,
    2316             :         }, /* PROT_CMD_PACKET */
    2317             :         {
    2318             :                 sizeof(MYSQLND_PACKET_RSET_HEADER),
    2319             :                 php_mysqlnd_rset_header_read, /* read */
    2320             :                 NULL, /* write */
    2321             :                 php_mysqlnd_rset_header_free_mem,
    2322             :         }, /* PROT_RSET_HEADER_PACKET */
    2323             :         {
    2324             :                 sizeof(MYSQLND_PACKET_RES_FIELD),
    2325             :                 php_mysqlnd_rset_field_read, /* read */
    2326             :                 NULL, /* write */
    2327             :                 php_mysqlnd_rset_field_free_mem,
    2328             :         }, /* PROT_RSET_FLD_PACKET */
    2329             :         {
    2330             :                 sizeof(MYSQLND_PACKET_ROW),
    2331             :                 php_mysqlnd_rowp_read, /* read */
    2332             :                 NULL, /* write */
    2333             :                 php_mysqlnd_rowp_free_mem,
    2334             :         }, /* PROT_ROW_PACKET */
    2335             :         {
    2336             :                 sizeof(MYSQLND_PACKET_STATS),
    2337             :                 php_mysqlnd_stats_read, /* read */
    2338             :                 NULL, /* write */
    2339             :                 php_mysqlnd_stats_free_mem,
    2340             :         }, /* PROT_STATS_PACKET */
    2341             :         {
    2342             :                 sizeof(MYSQLND_PACKET_PREPARE_RESPONSE),
    2343             :                 php_mysqlnd_prepare_read, /* read */
    2344             :                 NULL, /* write */
    2345             :                 php_mysqlnd_prepare_free_mem,
    2346             :         }, /* PROT_PREPARE_RESP_PACKET */
    2347             :         {
    2348             :                 sizeof(MYSQLND_PACKET_CHG_USER_RESPONSE),
    2349             :                 php_mysqlnd_chg_user_read, /* read */
    2350             :                 NULL, /* write */
    2351             :                 php_mysqlnd_chg_user_free_mem,
    2352             :         }, /* PROT_CHG_USER_RESP_PACKET */
    2353             :         {
    2354             :                 sizeof(MYSQLND_PACKET_SHA256_PK_REQUEST),
    2355             :                 NULL, /* read */
    2356             :                 php_mysqlnd_sha256_pk_request_write,
    2357             :                 php_mysqlnd_sha256_pk_request_free_mem,
    2358             :         }, /* PROT_SHA256_PK_REQUEST_PACKET */
    2359             :         {
    2360             :                 sizeof(MYSQLND_PACKET_SHA256_PK_REQUEST_RESPONSE),
    2361             :                 php_mysqlnd_sha256_pk_request_response_read,
    2362             :                 NULL, /* write */
    2363             :                 php_mysqlnd_sha256_pk_request_response_free_mem,
    2364             :         } /* PROT_SHA256_PK_REQUEST_RESPONSE_PACKET */
    2365             : };
    2366             : /* }}} */
    2367             : 
    2368             : 
    2369             : /* {{{ mysqlnd_protocol::get_greet_packet */
    2370             : static struct st_mysqlnd_packet_greet *
    2371        1692 : MYSQLND_METHOD(mysqlnd_protocol, get_greet_packet)(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const factory, const zend_bool persistent)
    2372             : {
    2373        1692 :         struct st_mysqlnd_packet_greet * packet = mnd_pecalloc(1, packet_methods[PROT_GREET_PACKET].struct_size, persistent);
    2374        1692 :         DBG_ENTER("mysqlnd_protocol::get_greet_packet");
    2375        1692 :         if (packet) {
    2376        1692 :                 packet->header.m = &packet_methods[PROT_GREET_PACKET];
    2377        1692 :                 packet->header.factory = factory;
    2378             : 
    2379        1692 :                 packet->header.protocol_frame_codec = factory->conn->protocol_frame_codec;
    2380        1692 :                 packet->header.vio = factory->conn->vio;
    2381        1692 :                 packet->header.stats = factory->conn->stats;
    2382        1692 :                 packet->header.error_info = factory->conn->error_info;
    2383        1692 :                 packet->header.connection_state = &factory->conn->state;
    2384             : 
    2385        1692 :                 packet->header.persistent = persistent;
    2386             :         }
    2387        1692 :         DBG_RETURN(packet);
    2388             : }
    2389             : /* }}} */
    2390             : 
    2391             : 
    2392             : /* {{{ mysqlnd_protocol::get_auth_packet */
    2393             : static struct st_mysqlnd_packet_auth *
    2394        3455 : MYSQLND_METHOD(mysqlnd_protocol, get_auth_packet)(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const factory, const zend_bool persistent)
    2395             : {
    2396        3455 :         struct st_mysqlnd_packet_auth * packet = mnd_pecalloc(1, packet_methods[PROT_AUTH_PACKET].struct_size, persistent);
    2397        3455 :         DBG_ENTER("mysqlnd_protocol::get_auth_packet");
    2398        3455 :         if (packet) {
    2399        3455 :                 packet->header.m = &packet_methods[PROT_AUTH_PACKET];
    2400        3455 :                 packet->header.factory = factory;
    2401             : 
    2402        3455 :                 packet->header.conn = factory->conn;
    2403        3455 :                 packet->header.protocol_frame_codec = factory->conn->protocol_frame_codec;
    2404        3455 :                 packet->header.vio = factory->conn->vio;
    2405        3455 :                 packet->header.stats = factory->conn->stats;
    2406        3455 :                 packet->header.error_info = factory->conn->error_info;
    2407        3455 :                 packet->header.connection_state = &factory->conn->state;
    2408             : 
    2409        3455 :                 packet->header.persistent = persistent;
    2410             :         }
    2411        3455 :         DBG_RETURN(packet);
    2412             : }
    2413             : /* }}} */
    2414             : 
    2415             : 
    2416             : /* {{{ mysqlnd_protocol::get_auth_response_packet */
    2417             : static struct st_mysqlnd_packet_auth_response *
    2418        1688 : MYSQLND_METHOD(mysqlnd_protocol, get_auth_response_packet)(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const factory, const zend_bool persistent)
    2419             : {
    2420        1688 :         struct st_mysqlnd_packet_auth_response * packet = mnd_pecalloc(1, packet_methods[PROT_AUTH_RESP_PACKET].struct_size, persistent);
    2421        1688 :         DBG_ENTER("mysqlnd_protocol::get_auth_response_packet");
    2422        1688 :         if (packet) {
    2423        1688 :                 packet->header.m = &packet_methods[PROT_AUTH_RESP_PACKET];
    2424        1688 :                 packet->header.factory = factory;
    2425             : 
    2426        1688 :                 packet->header.protocol_frame_codec = factory->conn->protocol_frame_codec;
    2427        1688 :                 packet->header.vio = factory->conn->vio;
    2428        1688 :                 packet->header.stats = factory->conn->stats;
    2429        1688 :                 packet->header.error_info = factory->conn->error_info;
    2430        1688 :                 packet->header.connection_state = &factory->conn->state;
    2431             : 
    2432        1688 :                 packet->header.persistent = persistent;
    2433             :         }
    2434        1688 :         DBG_RETURN(packet);
    2435             : }
    2436             : /* }}} */
    2437             : 
    2438             : 
    2439             : /* {{{ mysqlnd_protocol::get_change_auth_response_packet */
    2440             : static struct st_mysqlnd_packet_change_auth_response *
    2441           0 : MYSQLND_METHOD(mysqlnd_protocol, get_change_auth_response_packet)(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const factory, const zend_bool persistent)
    2442             : {
    2443           0 :         struct st_mysqlnd_packet_change_auth_response * packet = mnd_pecalloc(1, packet_methods[PROT_CHANGE_AUTH_RESP_PACKET].struct_size, persistent);
    2444           0 :         DBG_ENTER("mysqlnd_protocol::get_change_auth_response_packet");
    2445           0 :         if (packet) {
    2446           0 :                 packet->header.m = &packet_methods[PROT_CHANGE_AUTH_RESP_PACKET];
    2447           0 :                 packet->header.factory = factory;
    2448             : 
    2449           0 :                 packet->header.protocol_frame_codec = factory->conn->protocol_frame_codec;
    2450           0 :                 packet->header.vio = factory->conn->vio;
    2451           0 :                 packet->header.stats = factory->conn->stats;
    2452           0 :                 packet->header.error_info = factory->conn->error_info;
    2453           0 :                 packet->header.connection_state = &factory->conn->state;
    2454             : 
    2455           0 :                 packet->header.persistent = persistent;
    2456             :         }
    2457           0 :         DBG_RETURN(packet);
    2458             : }
    2459             : /* }}} */
    2460             : 
    2461             : 
    2462             : /* {{{ mysqlnd_protocol::get_ok_packet */
    2463             : static struct st_mysqlnd_packet_ok *
    2464          97 : MYSQLND_METHOD(mysqlnd_protocol, get_ok_packet)(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const factory, const zend_bool persistent)
    2465             : {
    2466          97 :         struct st_mysqlnd_packet_ok * packet = mnd_pecalloc(1, packet_methods[PROT_OK_PACKET].struct_size, persistent);
    2467          97 :         DBG_ENTER("mysqlnd_protocol::get_ok_packet");
    2468          97 :         if (packet) {
    2469          97 :                 packet->header.m = &packet_methods[PROT_OK_PACKET];
    2470          97 :                 packet->header.factory = factory;
    2471             : 
    2472          97 :                 packet->header.protocol_frame_codec = factory->conn->protocol_frame_codec;
    2473          97 :                 packet->header.vio = factory->conn->vio;
    2474          97 :                 packet->header.stats = factory->conn->stats;
    2475          97 :                 packet->header.error_info = factory->conn->error_info;
    2476          97 :                 packet->header.connection_state = &factory->conn->state;
    2477             : 
    2478          97 :                 packet->header.persistent = persistent;
    2479             :         }
    2480          97 :         DBG_RETURN(packet);
    2481             : }
    2482             : /* }}} */
    2483             : 
    2484             : 
    2485             : /* {{{ mysqlnd_protocol::get_eof_packet */
    2486             : static struct st_mysqlnd_packet_eof *
    2487        7728 : MYSQLND_METHOD(mysqlnd_protocol, get_eof_packet)(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const factory, const zend_bool persistent)
    2488             : {
    2489        7728 :         struct st_mysqlnd_packet_eof * packet = mnd_pecalloc(1, packet_methods[PROT_EOF_PACKET].struct_size, persistent);
    2490        7728 :         DBG_ENTER("mysqlnd_protocol::get_eof_packet");
    2491        7728 :         if (packet) {
    2492        7728 :                 packet->header.m = &packet_methods[PROT_EOF_PACKET];
    2493        7728 :                 packet->header.factory = factory;
    2494             : 
    2495        7728 :                 packet->header.protocol_frame_codec = factory->conn->protocol_frame_codec;
    2496        7728 :                 packet->header.vio = factory->conn->vio;
    2497        7728 :                 packet->header.stats = factory->conn->stats;
    2498        7728 :                 packet->header.error_info = factory->conn->error_info;
    2499        7728 :                 packet->header.connection_state = &factory->conn->state;
    2500             : 
    2501        7728 :                 packet->header.persistent = persistent;
    2502             :         }
    2503        7728 :         DBG_RETURN(packet);
    2504             : }
    2505             : /* }}} */
    2506             : 
    2507             : 
    2508             : /* {{{ mysqlnd_protocol::get_command_packet */
    2509             : static struct st_mysqlnd_packet_command *
    2510       37118 : MYSQLND_METHOD(mysqlnd_protocol, get_command_packet)(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const factory, const zend_bool persistent)
    2511             : {
    2512       37118 :         struct st_mysqlnd_packet_command * packet = mnd_pecalloc(1, packet_methods[PROT_CMD_PACKET].struct_size, persistent);
    2513       37118 :         DBG_ENTER("mysqlnd_protocol::get_command_packet");
    2514       37118 :         if (packet) {
    2515       37118 :                 packet->header.m = &packet_methods[PROT_CMD_PACKET];
    2516       37118 :                 packet->header.factory = factory;
    2517             : 
    2518       37118 :                 packet->header.protocol_frame_codec = factory->conn->protocol_frame_codec;
    2519       37118 :                 packet->header.vio = factory->conn->vio;
    2520       37118 :                 packet->header.stats = factory->conn->stats;
    2521       37118 :                 packet->header.error_info = factory->conn->error_info;
    2522       37118 :                 packet->header.connection_state = &factory->conn->state;
    2523             : 
    2524       37118 :                 packet->header.persistent = persistent;
    2525             :         }
    2526       37118 :         DBG_RETURN(packet);
    2527             : }
    2528             : /* }}} */
    2529             : 
    2530             : 
    2531             : /* {{{ mysqlnd_protocol::get_rset_packet */
    2532             : static struct st_mysqlnd_packet_rset_header *
    2533       26853 : MYSQLND_METHOD(mysqlnd_protocol, get_rset_header_packet)(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const factory, const zend_bool persistent)
    2534             : {
    2535       26853 :         struct st_mysqlnd_packet_rset_header * packet = mnd_pecalloc(1, packet_methods[PROT_RSET_HEADER_PACKET].struct_size, persistent);
    2536       26853 :         DBG_ENTER("mysqlnd_protocol::get_rset_header_packet");
    2537       26853 :         if (packet) {
    2538       26853 :                 packet->header.m = &packet_methods[PROT_RSET_HEADER_PACKET];
    2539       26853 :                 packet->header.factory = factory;
    2540             : 
    2541       26853 :                 packet->header.protocol_frame_codec = factory->conn->protocol_frame_codec;
    2542       26853 :                 packet->header.vio = factory->conn->vio;
    2543       26853 :                 packet->header.stats = factory->conn->stats;
    2544       26853 :                 packet->header.error_info = factory->conn->error_info;
    2545       26853 :                 packet->header.connection_state = &factory->conn->state;
    2546             : 
    2547       26853 :                 packet->header.persistent = persistent;
    2548             :         }
    2549       26853 :         DBG_RETURN(packet);
    2550             : }
    2551             : /* }}} */
    2552             : 
    2553             : 
    2554             : /* {{{ mysqlnd_protocol::get_result_field_packet */
    2555             : static struct st_mysqlnd_packet_res_field *
    2556        7694 : MYSQLND_METHOD(mysqlnd_protocol, get_result_field_packet)(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const factory, const zend_bool persistent)
    2557             : {
    2558        7694 :         struct st_mysqlnd_packet_res_field * packet = mnd_pecalloc(1, packet_methods[PROT_RSET_FLD_PACKET].struct_size, persistent);
    2559        7694 :         DBG_ENTER("mysqlnd_protocol::get_result_field_packet");
    2560        7694 :         if (packet) {
    2561        7694 :                 packet->header.m = &packet_methods[PROT_RSET_FLD_PACKET];
    2562        7694 :                 packet->header.factory = factory;
    2563             : 
    2564        7694 :                 packet->header.protocol_frame_codec = factory->conn->protocol_frame_codec;
    2565        7694 :                 packet->header.vio = factory->conn->vio;
    2566        7694 :                 packet->header.stats = factory->conn->stats;
    2567        7694 :                 packet->header.error_info = factory->conn->error_info;
    2568        7694 :                 packet->header.connection_state = &factory->conn->state;
    2569             : 
    2570        7694 :                 packet->header.persistent = persistent;
    2571             :         }
    2572        7694 :         DBG_RETURN(packet);
    2573             : }
    2574             : /* }}} */
    2575             : 
    2576             : 
    2577             : /* {{{ mysqlnd_protocol::get_row_packet */
    2578             : static struct st_mysqlnd_packet_row *
    2579        4431 : MYSQLND_METHOD(mysqlnd_protocol, get_row_packet)(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const factory, const zend_bool persistent)
    2580             : {
    2581        4431 :         struct st_mysqlnd_packet_row * packet = mnd_pecalloc(1, packet_methods[PROT_ROW_PACKET].struct_size, persistent);
    2582        4431 :         DBG_ENTER("mysqlnd_protocol::get_row_packet");
    2583        4431 :         if (packet) {
    2584        4431 :                 packet->header.m = &packet_methods[PROT_ROW_PACKET];
    2585        4431 :                 packet->header.factory = factory;
    2586             : 
    2587        4431 :                 packet->header.conn = factory->conn;
    2588        4431 :                 packet->header.protocol_frame_codec = factory->conn->protocol_frame_codec;
    2589        4431 :                 packet->header.vio = factory->conn->vio;
    2590        4431 :                 packet->header.stats = factory->conn->stats;
    2591        4431 :                 packet->header.error_info = factory->conn->error_info;
    2592        4431 :                 packet->header.connection_state = &factory->conn->state;
    2593             : 
    2594        4431 :                 packet->header.persistent = persistent;
    2595             :         }
    2596        4431 :         DBG_RETURN(packet);
    2597             : }
    2598             : /* }}} */
    2599             : 
    2600             : 
    2601             : /* {{{ mysqlnd_protocol::get_stats_packet */
    2602             : static struct st_mysqlnd_packet_stats *
    2603          15 : MYSQLND_METHOD(mysqlnd_protocol, get_stats_packet)(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const factory, const zend_bool persistent)
    2604             : {
    2605          15 :         struct st_mysqlnd_packet_stats * packet = mnd_pecalloc(1, packet_methods[PROT_STATS_PACKET].struct_size, persistent);
    2606          15 :         DBG_ENTER("mysqlnd_protocol::get_stats_packet");
    2607          15 :         if (packet) {
    2608          15 :                 packet->header.m = &packet_methods[PROT_STATS_PACKET];
    2609          15 :                 packet->header.factory = factory;
    2610             : 
    2611          15 :                 packet->header.protocol_frame_codec = factory->conn->protocol_frame_codec;
    2612          15 :                 packet->header.vio = factory->conn->vio;
    2613          15 :                 packet->header.stats = factory->conn->stats;
    2614          15 :                 packet->header.error_info = factory->conn->error_info;
    2615          15 :                 packet->header.connection_state = &factory->conn->state;
    2616             : 
    2617          15 :                 packet->header.persistent = persistent;
    2618             :         }
    2619          15 :         DBG_RETURN(packet);
    2620             : }
    2621             : /* }}} */
    2622             : 
    2623             : 
    2624             : /* {{{ mysqlnd_protocol::get_prepare_response_packet */
    2625             : static struct st_mysqlnd_packet_prepare_response *
    2626        4250 : MYSQLND_METHOD(mysqlnd_protocol, get_prepare_response_packet)(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const factory, const zend_bool persistent)
    2627             : {
    2628        4250 :         struct st_mysqlnd_packet_prepare_response * packet = mnd_pecalloc(1, packet_methods[PROT_PREPARE_RESP_PACKET].struct_size, persistent);
    2629        4250 :         DBG_ENTER("mysqlnd_protocol::get_prepare_response_packet");
    2630        4250 :         if (packet) {
    2631        4250 :                 packet->header.m = &packet_methods[PROT_PREPARE_RESP_PACKET];
    2632        4250 :                 packet->header.factory = factory;
    2633             : 
    2634        4250 :                 packet->header.protocol_frame_codec = factory->conn->protocol_frame_codec;
    2635        4250 :                 packet->header.vio = factory->conn->vio;
    2636        4250 :                 packet->header.stats = factory->conn->stats;
    2637        4250 :                 packet->header.error_info = factory->conn->error_info;
    2638        4250 :                 packet->header.connection_state = &factory->conn->state;
    2639             : 
    2640        4250 :                 packet->header.persistent = persistent;
    2641             :         }
    2642        4250 :         DBG_RETURN(packet);
    2643             : }
    2644             : /* }}} */
    2645             : 
    2646             : 
    2647             : /* {{{ mysqlnd_protocol::get_change_user_response_packet */
    2648             : static struct st_mysqlnd_packet_chg_user_resp*
    2649          75 : MYSQLND_METHOD(mysqlnd_protocol, get_change_user_response_packet)(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const factory, const zend_bool persistent)
    2650             : {
    2651          75 :         struct st_mysqlnd_packet_chg_user_resp * packet = mnd_pecalloc(1, packet_methods[PROT_CHG_USER_RESP_PACKET].struct_size, persistent);
    2652          75 :         DBG_ENTER("mysqlnd_protocol::get_change_user_response_packet");
    2653          75 :         if (packet) {
    2654          75 :                 packet->header.m = &packet_methods[PROT_CHG_USER_RESP_PACKET];
    2655          75 :                 packet->header.factory = factory;
    2656             : 
    2657          75 :                 packet->header.protocol_frame_codec = factory->conn->protocol_frame_codec;
    2658          75 :                 packet->header.vio = factory->conn->vio;
    2659          75 :                 packet->header.stats = factory->conn->stats;
    2660          75 :                 packet->header.error_info = factory->conn->error_info;
    2661          75 :                 packet->header.connection_state = &factory->conn->state;
    2662             : 
    2663          75 :                 packet->header.persistent = persistent;
    2664             :         }
    2665          75 :         DBG_RETURN(packet);
    2666             : }
    2667             : /* }}} */
    2668             : 
    2669             : 
    2670             : /* {{{ mysqlnd_protocol::get_sha256_pk_request_packet */
    2671             : static struct st_mysqlnd_packet_sha256_pk_request *
    2672           0 : MYSQLND_METHOD(mysqlnd_protocol, get_sha256_pk_request_packet)(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const factory, const zend_bool persistent)
    2673             : {
    2674           0 :         struct st_mysqlnd_packet_sha256_pk_request * packet = mnd_pecalloc(1, packet_methods[PROT_SHA256_PK_REQUEST_PACKET].struct_size, persistent);
    2675           0 :         DBG_ENTER("mysqlnd_protocol::get_sha256_pk_request_packet");
    2676           0 :         if (packet) {
    2677           0 :                 packet->header.m = &packet_methods[PROT_SHA256_PK_REQUEST_PACKET];
    2678           0 :                 packet->header.factory = factory;
    2679             : 
    2680           0 :                 packet->header.protocol_frame_codec = factory->conn->protocol_frame_codec;
    2681           0 :                 packet->header.vio = factory->conn->vio;
    2682           0 :                 packet->header.stats = factory->conn->stats;
    2683           0 :                 packet->header.error_info = factory->conn->error_info;
    2684           0 :                 packet->header.connection_state = &factory->conn->state;
    2685             : 
    2686           0 :                 packet->header.persistent = persistent;
    2687             :         }
    2688           0 :         DBG_RETURN(packet);
    2689             : }
    2690             : /* }}} */
    2691             : 
    2692             : 
    2693             : /* {{{ mysqlnd_protocol::get_sha256_pk_request_response_packet */
    2694             : static struct st_mysqlnd_packet_sha256_pk_request_response *
    2695           0 : MYSQLND_METHOD(mysqlnd_protocol, get_sha256_pk_request_response_packet)(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const factory, const zend_bool persistent)
    2696             : {
    2697           0 :         struct st_mysqlnd_packet_sha256_pk_request_response * packet = mnd_pecalloc(1, packet_methods[PROT_SHA256_PK_REQUEST_RESPONSE_PACKET].struct_size, persistent);
    2698           0 :         DBG_ENTER("mysqlnd_protocol::get_sha256_pk_request_response_packet");
    2699           0 :         if (packet) {
    2700           0 :                 packet->header.m = &packet_methods[PROT_SHA256_PK_REQUEST_RESPONSE_PACKET];
    2701           0 :                 packet->header.factory = factory;
    2702             : 
    2703           0 :                 packet->header.protocol_frame_codec = factory->conn->protocol_frame_codec;
    2704           0 :                 packet->header.vio = factory->conn->vio;
    2705           0 :                 packet->header.stats = factory->conn->stats;
    2706           0 :                 packet->header.error_info = factory->conn->error_info;
    2707           0 :                 packet->header.connection_state = &factory->conn->state;
    2708             : 
    2709           0 :                 packet->header.persistent = persistent;
    2710             :         }
    2711           0 :         DBG_RETURN(packet);
    2712             : }
    2713             : /* }}} */
    2714             : 
    2715             : 
    2716             : /* {{{ mysqlnd_protocol::send_command */
    2717             : static enum_func_status
    2718       37150 : MYSQLND_METHOD(mysqlnd_protocol, send_command)(
    2719             :                 MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * payload_decoder_factory,
    2720             :                 const enum php_mysqlnd_server_command command,
    2721             :                 const zend_uchar * const arg, const size_t arg_len,
    2722             :                 const zend_bool silent,
    2723             : 
    2724             :                 struct st_mysqlnd_connection_state * connection_state,
    2725             :                 MYSQLND_ERROR_INFO      * error_info,
    2726             :                 MYSQLND_UPSERT_STATUS * upsert_status,
    2727             :                 MYSQLND_STATS * stats,
    2728             :                 func_mysqlnd_conn_data__send_close send_close,
    2729             :                 void * send_close_ctx)
    2730             : {
    2731       37150 :         enum_func_status ret = PASS;
    2732       37150 :         MYSQLND_PACKET_COMMAND * cmd_packet = NULL;
    2733       37150 :         DBG_ENTER("mysqlnd_protocol::send_command");
    2734       37150 :         DBG_INF_FMT("command=%s silent=%u", mysqlnd_command_to_text[command], silent);
    2735       37150 :         DBG_INF_FMT("server_status=%u", UPSERT_STATUS_GET_SERVER_STATUS(upsert_status));
    2736       37150 :         DBG_INF_FMT("sending %u bytes", arg_len + 1); /* + 1 is for the command */
    2737       37150 :         enum mysqlnd_connection_state state = connection_state->m->get(connection_state);
    2738             : 
    2739       37150 :         switch (state) {
    2740             :                 case CONN_READY:
    2741       37118 :                         break;
    2742             :                 case CONN_QUIT_SENT:
    2743          12 :                         SET_CLIENT_ERROR(error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
    2744          12 :                         DBG_ERR("Server is gone");
    2745          12 :                         DBG_RETURN(FAIL);
    2746             :                 default:
    2747          20 :                         SET_CLIENT_ERROR(error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
    2748          20 :                         DBG_ERR_FMT("Command out of sync. State=%u", state);
    2749          20 :                         DBG_RETURN(FAIL);
    2750             :         }
    2751             : 
    2752       37118 :         UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(upsert_status);
    2753       37118 :         SET_EMPTY_ERROR(error_info);
    2754             : 
    2755       37118 :         cmd_packet = payload_decoder_factory->m.get_command_packet(payload_decoder_factory, FALSE);
    2756       37118 :         if (!cmd_packet) {
    2757           0 :                 SET_OOM_ERROR(error_info);
    2758           0 :                 DBG_RETURN(FAIL);
    2759             :         }
    2760             : 
    2761       37118 :         cmd_packet->command = command;
    2762       37118 :         if (arg && arg_len) {
    2763       35424 :                 cmd_packet->argument.s = (char *) arg;
    2764       35424 :                 cmd_packet->argument.l = arg_len;
    2765             :         }
    2766             : 
    2767       37118 :         MYSQLND_INC_CONN_STATISTIC(stats, STAT_COM_QUIT + command - 1 /* because of COM_SLEEP */ );
    2768             : 
    2769       37118 :         if (! PACKET_WRITE(cmd_packet)) {
    2770           9 :                 if (!silent) {
    2771           3 :                         DBG_ERR_FMT("Error while sending %s packet", mysqlnd_command_to_text[command]);
    2772           3 :                         php_error(E_WARNING, "Error while sending %s packet. PID=%d", mysqlnd_command_to_text[command], getpid());
    2773             :                 }
    2774           9 :                 connection_state->m->set(connection_state, CONN_QUIT_SENT);
    2775           9 :                 send_close(send_close_ctx);
    2776           9 :                 DBG_ERR("Server is gone");
    2777           9 :                 ret = FAIL;
    2778             :         }
    2779       37118 :         PACKET_FREE(cmd_packet);
    2780       37118 :         DBG_RETURN(ret);
    2781             : }
    2782             : /* }}} */
    2783             : 
    2784             : 
    2785             : /* {{{ mysqlnd_protocol::send_command_handle_OK */
    2786             : static enum_func_status
    2787          97 : MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_OK)(
    2788             :                                                 MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const payload_decoder_factory,
    2789             :                                                 MYSQLND_ERROR_INFO * const error_info,
    2790             :                                                 MYSQLND_UPSERT_STATUS * const upsert_status,
    2791             :                                                 const zend_bool ignore_upsert_status,  /* actually used only by LOAD DATA. COM_QUERY and COM_EXECUTE handle the responses themselves */
    2792             :                                                 MYSQLND_STRING * const last_message,
    2793             :                                                 const zend_bool last_message_persistent)
    2794             : {
    2795          97 :         enum_func_status ret = FAIL;
    2796          97 :         MYSQLND_PACKET_OK * ok_response = payload_decoder_factory->m.get_ok_packet(payload_decoder_factory, FALSE);
    2797             : 
    2798          97 :         DBG_ENTER("mysqlnd_protocol::send_command_handle_OK");
    2799          97 :         if (!ok_response) {
    2800           0 :                 SET_OOM_ERROR(error_info);
    2801           0 :                 DBG_RETURN(FAIL);
    2802             :         }
    2803          97 :         if (FAIL == (ret = PACKET_READ(ok_response))) {
    2804           0 :                 DBG_INF("Error while reading OK packet");
    2805           0 :                 SET_CLIENT_ERROR(error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet");
    2806           0 :                 goto end;
    2807             :         }
    2808          97 :         DBG_INF_FMT("OK from server");
    2809          97 :         if (0xFF == ok_response->field_count) {
    2810             :                 /* The server signalled error. Set the error */
    2811           8 :                 SET_CLIENT_ERROR(error_info, ok_response->error_no, ok_response->sqlstate, ok_response->error);
    2812           8 :                 ret = FAIL;
    2813             :                 /*
    2814             :                   Cover a protocol design error: error packet does not
    2815             :                   contain the server status. Therefore, the client has no way
    2816             :                   to find out whether there are more result sets of
    2817             :                   a multiple-result-set statement pending. Luckily, in 5.0 an
    2818             :                   error always aborts execution of a statement, wherever it is
    2819             :                   a multi-statement or a stored procedure, so it should be
    2820             :                   safe to unconditionally turn off the flag here.
    2821             :                 */
    2822           8 :                 upsert_status->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
    2823           8 :                 UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(upsert_status);
    2824             :         } else {
    2825          89 :                 SET_NEW_MESSAGE(last_message->s, last_message->l,
    2826             :                                                 ok_response->message, ok_response->message_len,
    2827             :                                                 last_message_persistent);
    2828          89 :                 if (!ignore_upsert_status) {
    2829          12 :                         UPSERT_STATUS_RESET(upsert_status);
    2830          12 :                         UPSERT_STATUS_SET_WARNINGS(upsert_status, ok_response->warning_count);
    2831          12 :                         UPSERT_STATUS_SET_SERVER_STATUS(upsert_status, ok_response->server_status);
    2832          12 :                         UPSERT_STATUS_SET_AFFECTED_ROWS(upsert_status, ok_response->affected_rows);
    2833          12 :                         UPSERT_STATUS_SET_LAST_INSERT_ID(upsert_status, ok_response->last_insert_id);
    2834             :                 } else {
    2835             :                         /* LOAD DATA */
    2836             :                 }
    2837             :         }
    2838             : end:
    2839          97 :         PACKET_FREE(ok_response);
    2840          97 :         DBG_INF(ret == PASS ? "PASS":"FAIL");
    2841          97 :         DBG_RETURN(ret);
    2842             : }
    2843             : /* }}} */
    2844             : 
    2845             : 
    2846             : /* {{{ mysqlnd_protocol::send_command_handle_EOF */
    2847             : static enum_func_status
    2848          34 : MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_EOF)(
    2849             :                                                 MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const payload_decoder_factory,
    2850             :                                                 MYSQLND_ERROR_INFO * const error_info,
    2851             :                                                 MYSQLND_UPSERT_STATUS * const upsert_status)
    2852             : {
    2853          34 :         enum_func_status ret = FAIL;
    2854          34 :         MYSQLND_PACKET_EOF * response = payload_decoder_factory->m.get_eof_packet(payload_decoder_factory, FALSE);
    2855             : 
    2856          34 :         DBG_ENTER("mysqlnd_protocol::send_command_handle_EOF");
    2857             : 
    2858          34 :         if (!response) {
    2859           0 :                 SET_OOM_ERROR(error_info);
    2860           0 :                 DBG_RETURN(FAIL);
    2861             :         }
    2862          34 :         if (FAIL == (ret = PACKET_READ(response))) {
    2863           0 :                 DBG_INF("Error while reading EOF packet");
    2864           0 :                 SET_CLIENT_ERROR(error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet");
    2865          34 :         } else if (0xFF == response->field_count) {
    2866             :                 /* The server signalled error. Set the error */
    2867           2 :                 DBG_INF_FMT("Error_no=%d SQLstate=%s Error=%s", response->error_no, response->sqlstate, response->error);
    2868             : 
    2869           2 :                 SET_CLIENT_ERROR(error_info, response->error_no, response->sqlstate, response->error);
    2870             : 
    2871           2 :                 UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(upsert_status);
    2872          32 :         } else if (0xFE != response->field_count) {
    2873           0 :                 SET_CLIENT_ERROR(error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet");
    2874           0 :                 DBG_ERR_FMT("EOF packet expected, field count wasn't 0xFE but 0x%2X", response->field_count);
    2875           0 :                 php_error_docref(NULL, E_WARNING, "EOF packet expected, field count wasn't 0xFE but 0x%2X", response->field_count);
    2876             :         } else {
    2877          32 :                 DBG_INF_FMT("EOF from server");
    2878             :         }
    2879          34 :         PACKET_FREE(response);
    2880             : 
    2881          34 :         DBG_INF(ret == PASS ? "PASS":"FAIL");
    2882          34 :         DBG_RETURN(ret);
    2883             : }
    2884             : /* }}} */
    2885             : 
    2886             : 
    2887             : /* {{{ send_command_handle_response */
    2888             : static enum_func_status
    2889         131 : MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_response)(
    2890             :                 MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * payload_decoder_factory,
    2891             :                 const enum mysqlnd_packet_type ok_packet,
    2892             :                 const zend_bool silent,
    2893             :                 const enum php_mysqlnd_server_command command,
    2894             :                 const zend_bool ignore_upsert_status, /* actually used only by LOAD DATA. COM_QUERY and COM_EXECUTE handle the responses themselves */
    2895             : 
    2896             :                 MYSQLND_ERROR_INFO      * error_info,
    2897             :                 MYSQLND_UPSERT_STATUS * upsert_status,
    2898             :                 MYSQLND_STRING * last_message,
    2899             :                 zend_bool last_message_persistent
    2900             :         )
    2901             : {
    2902         131 :         enum_func_status ret = FAIL;
    2903             : 
    2904         131 :         DBG_ENTER("mysqlnd_protocol::send_command_handle_response");
    2905         131 :         DBG_INF_FMT("silent=%u packet=%u command=%s", silent, ok_packet, mysqlnd_command_to_text[command]);
    2906             : 
    2907         131 :         switch (ok_packet) {
    2908             :                 case PROT_OK_PACKET:
    2909          97 :                         ret = payload_decoder_factory->m.send_command_handle_OK(payload_decoder_factory, error_info, upsert_status, ignore_upsert_status, last_message, last_message_persistent);
    2910          97 :                         break;
    2911             :                 case PROT_EOF_PACKET:
    2912          34 :                         ret = payload_decoder_factory->m.send_command_handle_EOF(payload_decoder_factory, error_info, upsert_status);
    2913          34 :                         break;
    2914             :                 default:
    2915           0 :                         SET_CLIENT_ERROR(error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet");
    2916           0 :                         php_error_docref(NULL, E_ERROR, "Wrong response packet %u passed to the function", ok_packet);
    2917             :                         break;
    2918             :         }
    2919         131 :         if (!silent && error_info->error_no == CR_MALFORMED_PACKET) {
    2920           0 :                 php_error_docref(NULL, E_WARNING, "Error while reading %s's response packet. PID=%d", mysqlnd_command_to_text[command], getpid());
    2921             :         }
    2922         131 :         DBG_INF(ret == PASS ? "PASS":"FAIL");
    2923         131 :         DBG_RETURN(ret);
    2924             : }
    2925             : /* }}} */
    2926             : 
    2927             : 
    2928             : MYSQLND_CLASS_METHODS_START(mysqlnd_protocol_payload_decoder_factory)
    2929             :         MYSQLND_METHOD(mysqlnd_protocol, get_greet_packet),
    2930             :         MYSQLND_METHOD(mysqlnd_protocol, get_auth_packet),
    2931             :         MYSQLND_METHOD(mysqlnd_protocol, get_auth_response_packet),
    2932             :         MYSQLND_METHOD(mysqlnd_protocol, get_change_auth_response_packet),
    2933             :         MYSQLND_METHOD(mysqlnd_protocol, get_ok_packet),
    2934             :         MYSQLND_METHOD(mysqlnd_protocol, get_command_packet),
    2935             :         MYSQLND_METHOD(mysqlnd_protocol, get_eof_packet),
    2936             :         MYSQLND_METHOD(mysqlnd_protocol, get_rset_header_packet),
    2937             :         MYSQLND_METHOD(mysqlnd_protocol, get_result_field_packet),
    2938             :         MYSQLND_METHOD(mysqlnd_protocol, get_row_packet),
    2939             :         MYSQLND_METHOD(mysqlnd_protocol, get_stats_packet),
    2940             :         MYSQLND_METHOD(mysqlnd_protocol, get_prepare_response_packet),
    2941             :         MYSQLND_METHOD(mysqlnd_protocol, get_change_user_response_packet),
    2942             :         MYSQLND_METHOD(mysqlnd_protocol, get_sha256_pk_request_packet),
    2943             :         MYSQLND_METHOD(mysqlnd_protocol, get_sha256_pk_request_response_packet),
    2944             : 
    2945             :         MYSQLND_METHOD(mysqlnd_protocol, send_command),
    2946             :         MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_response),
    2947             :         MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_OK),
    2948             :         MYSQLND_METHOD(mysqlnd_protocol, send_command_handle_EOF),
    2949             : MYSQLND_CLASS_METHODS_END;
    2950             : 
    2951             : 
    2952             : /* {{{ mysqlnd_protocol_payload_decoder_factory_init */
    2953             : PHPAPI MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY *
    2954        1731 : mysqlnd_protocol_payload_decoder_factory_init(MYSQLND_CONN_DATA * conn, const zend_bool persistent)
    2955             : {
    2956             :         MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * ret;
    2957        1731 :         DBG_ENTER("mysqlnd_protocol_payload_decoder_factory_init");
    2958        1731 :         ret = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory).get_protocol_payload_decoder_factory(conn, persistent);
    2959        1731 :         DBG_RETURN(ret);
    2960             : }
    2961             : /* }}} */
    2962             : 
    2963             : 
    2964             : /* {{{ mysqlnd_protocol_payload_decoder_factory_free */
    2965             : PHPAPI void
    2966        1723 : mysqlnd_protocol_payload_decoder_factory_free(MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * const factory)
    2967             : {
    2968        1723 :         DBG_ENTER("mysqlnd_protocol_payload_decoder_factory_free");
    2969             : 
    2970        1723 :         if (factory) {
    2971        1723 :                 zend_bool pers = factory->persistent;
    2972        1723 :                 mnd_pefree(factory, pers);
    2973             :         }
    2974        1723 :         DBG_VOID_RETURN;
    2975             : }
    2976             : /* }}} */
    2977             : 
    2978             : 
    2979             : /*
    2980             :  * Local variables:
    2981             :  * tab-width: 4
    2982             :  * c-basic-offset: 4
    2983             :  * End:
    2984             :  * vim600: noet sw=4 ts=4 fdm=marker
    2985             :  * vim<600: noet sw=4 ts=4
    2986             :  */

Generated by: LCOV version 1.10

Generated at Sat, 25 Jun 2016 07:08:58 +0000 (4 days ago)

Copyright © 2005-2016 The PHP Group
All rights reserved.