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: 884 1076 82.2 %
Date: 2014-09-21 Functions: 46 49 93.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   +----------------------------------------------------------------------+
       3             :   | PHP Version 5                                                        |
       4             :   +----------------------------------------------------------------------+
       5             :   | Copyright (c) 2006-2014 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             : 
      21             : /* $Id$ */
      22             : #include "php.h"
      23             : #include "php_globals.h"
      24             : #include "mysqlnd.h"
      25             : #include "mysqlnd_priv.h"
      26             : #include "mysqlnd_wireprotocol.h"
      27             : #include "mysqlnd_statistics.h"
      28             : #include "mysqlnd_debug.h"
      29             : #include "zend_ini.h"
      30             : 
      31             : #define MYSQLND_SILENT 1
      32             : 
      33             : #define MYSQLND_DUMP_HEADER_N_BODY
      34             : 
      35             : #define PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_size, packet_type_as_text, packet_type) \
      36             :         { \
      37             :                 DBG_INF_FMT("buf=%p size=%u", (buf), (buf_size)); \
      38             :                 if (FAIL == mysqlnd_read_header((conn)->net, &((packet)->header), (conn)->stats, ((conn)->error_info) TSRMLS_CC)) {\
      39             :                         CONN_SET_STATE(conn, CONN_QUIT_SENT); \
      40             :                         SET_CLIENT_ERROR(*conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);\
      41             :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", mysqlnd_server_gone); \
      42             :                         DBG_ERR_FMT("Can't read %s's header", (packet_type_as_text)); \
      43             :                         DBG_RETURN(FAIL);\
      44             :                 }\
      45             :                 if ((buf_size) < (packet)->header.size) { \
      46             :                         DBG_ERR_FMT("Packet buffer %u wasn't big enough %u, %u bytes will be unread", \
      47             :                                                 (buf_size), (packet)->header.size, (packet)->header.size - (buf_size)); \
      48             :                                                 DBG_RETURN(FAIL); \
      49             :                 }\
      50             :                 if (FAIL == conn->net->m.receive_ex((conn)->net, (buf), (packet)->header.size, (conn)->stats, ((conn)->error_info) TSRMLS_CC)) { \
      51             :                         CONN_SET_STATE(conn, CONN_QUIT_SENT); \
      52             :                         SET_CLIENT_ERROR(*conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);\
      53             :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", mysqlnd_server_gone); \
      54             :                         DBG_ERR_FMT("Empty '%s' packet body", (packet_type_as_text)); \
      55             :                         DBG_RETURN(FAIL);\
      56             :                 } \
      57             :                 MYSQLND_INC_CONN_STATISTIC_W_VALUE2(conn->stats, packet_type_to_statistic_byte_count[packet_type], \
      58             :                                                                                         MYSQLND_HEADER_SIZE + (packet)->header.size, \
      59             :                                                                                         packet_type_to_statistic_packet_count[packet_type], \
      60             :                                                                                         1); \
      61             :         }
      62             : 
      63             : 
      64             : #define BAIL_IF_NO_MORE_DATA \
      65             :         if ((size_t)(p - begin) > packet->header.size) { \
      66             :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Premature end of data (mysqlnd_wireprotocol.c:%u)", __LINE__); \
      67             :                 goto premature_end; \
      68             :         } \
      69             : 
      70             : 
      71             : static const char *unknown_sqlstate= "HY000";
      72             : 
      73             : const char * const mysqlnd_empty_string = "";
      74             : 
      75             : /* Used in mysqlnd_debug.c */
      76             : const char mysqlnd_read_header_name[]   = "mysqlnd_read_header";
      77             : const char mysqlnd_read_body_name[]             = "mysqlnd_read_body";
      78             : 
      79             : 
      80             : #define ERROR_MARKER 0xFF
      81             : #define EODATA_MARKER 0xFE
      82             : 
      83             : /* {{{ mysqlnd_command_to_text
      84             :  */
      85             : const char * const mysqlnd_command_to_text[COM_END] =
      86             : {
      87             :   "SLEEP", "QUIT", "INIT_DB", "QUERY", "FIELD_LIST",
      88             :   "CREATE_DB", "DROP_DB", "REFRESH", "SHUTDOWN", "STATISTICS",
      89             :   "PROCESS_INFO", "CONNECT", "PROCESS_KILL", "DEBUG", "PING",
      90             :   "TIME", "DELAYED_INSERT", "CHANGE_USER", "BINLOG_DUMP",
      91             :   "TABLE_DUMP", "CONNECT_OUT", "REGISTER_SLAVE",
      92             :   "STMT_PREPARE", "STMT_EXECUTE", "STMT_SEND_LONG_DATA", "STMT_CLOSE",
      93             :   "STMT_RESET", "SET_OPTION", "STMT_FETCH", "DAEMON", "BINLOG_DUMP_GTID",
      94             :   "RESET_CONNECTION"
      95             : };
      96             : /* }}} */
      97             : 
      98             : 
      99             : 
     100             : static enum_mysqlnd_collected_stats packet_type_to_statistic_byte_count[PROT_LAST] =
     101             : {
     102             :         STAT_LAST,
     103             :         STAT_LAST,
     104             :         STAT_BYTES_RECEIVED_OK,
     105             :         STAT_BYTES_RECEIVED_EOF,
     106             :         STAT_LAST,
     107             :         STAT_BYTES_RECEIVED_RSET_HEADER,
     108             :         STAT_BYTES_RECEIVED_RSET_FIELD_META,
     109             :         STAT_BYTES_RECEIVED_RSET_ROW,
     110             :         STAT_BYTES_RECEIVED_PREPARE_RESPONSE,
     111             :         STAT_BYTES_RECEIVED_CHANGE_USER,
     112             : };
     113             : 
     114             : static enum_mysqlnd_collected_stats packet_type_to_statistic_packet_count[PROT_LAST] =
     115             : {
     116             :         STAT_LAST,
     117             :         STAT_LAST,
     118             :         STAT_PACKETS_RECEIVED_OK,
     119             :         STAT_PACKETS_RECEIVED_EOF,
     120             :         STAT_LAST,
     121             :         STAT_PACKETS_RECEIVED_RSET_HEADER,
     122             :         STAT_PACKETS_RECEIVED_RSET_FIELD_META,
     123             :         STAT_PACKETS_RECEIVED_RSET_ROW,
     124             :         STAT_PACKETS_RECEIVED_PREPARE_RESPONSE,
     125             :         STAT_PACKETS_RECEIVED_CHANGE_USER,
     126             : };
     127             : 
     128             : 
     129             : /* {{{ php_mysqlnd_net_field_length
     130             :    Get next field's length */
     131             : unsigned long
     132      310399 : php_mysqlnd_net_field_length(zend_uchar **packet)
     133             : {
     134      310399 :         register zend_uchar *p= (zend_uchar *)*packet;
     135             : 
     136      310399 :         if (*p < 251) {
     137      277322 :                 (*packet)++;
     138      277322 :                 return (unsigned long) *p;
     139             :         }
     140             : 
     141       33077 :         switch (*p) {
     142             :                 case 251:
     143         749 :                         (*packet)++;
     144         749 :                         return MYSQLND_NULL_LENGTH;
     145             :                 case 252:
     146       32309 :                         (*packet) += 3;
     147       32309 :                         return (unsigned long) uint2korr(p+1);
     148             :                 case 253:
     149          18 :                         (*packet) += 4;
     150          18 :                         return (unsigned long) uint3korr(p+1);
     151             :                 default:
     152           1 :                         (*packet) += 9;
     153           1 :                         return (unsigned long) uint4korr(p+1);
     154             :         }
     155             : }
     156             : /* }}} */
     157             : 
     158             : 
     159             : /* {{{ php_mysqlnd_net_field_length_ll
     160             :    Get next field's length */
     161             : uint64_t
     162       45192 : php_mysqlnd_net_field_length_ll(zend_uchar **packet)
     163             : {
     164       45192 :         register zend_uchar *p= (zend_uchar *)*packet;
     165             : 
     166       45192 :         if (*p < 251) {
     167       45181 :                 (*packet)++;
     168       45181 :                 return (uint64_t) *p;
     169             :         }
     170             : 
     171          11 :         switch (*p) {
     172             :                 case 251:
     173           0 :                         (*packet)++;
     174           0 :                         return (uint64_t) MYSQLND_NULL_LENGTH;
     175             :                 case 252:
     176           9 :                         (*packet) += 3;
     177           9 :                         return (uint64_t) uint2korr(p + 1);
     178             :                 case 253:
     179           0 :                         (*packet) += 4;
     180           0 :                         return (uint64_t) uint3korr(p + 1);
     181             :                 default:
     182           2 :                         (*packet) += 9;
     183           2 :                         return (uint64_t) uint8korr(p + 1);
     184             :         }
     185             : }
     186             : /* }}} */
     187             : 
     188             : 
     189             : /* {{{ php_mysqlnd_net_store_length */
     190             : zend_uchar *
     191         657 : php_mysqlnd_net_store_length(zend_uchar *packet, uint64_t length)
     192             : {
     193         657 :         if (length < (uint64_t) L64(251)) {
     194         580 :                 *packet = (zend_uchar) length;
     195         580 :                 return packet + 1;
     196             :         }
     197             : 
     198          77 :         if (length < (uint64_t) L64(65536)) {
     199          73 :                 *packet++ = 252;
     200          73 :                 int2store(packet,(unsigned int) length);
     201          73 :                 return packet + 2;
     202             :         }
     203             : 
     204           4 :         if (length < (uint64_t) L64(16777216)) {
     205           4 :                 *packet++ = 253;
     206           4 :                 int3store(packet,(ulong) length);
     207           4 :                 return packet + 3;
     208             :         }
     209           0 :         *packet++ = 254;
     210           0 :         int8store(packet, length);
     211           0 :         return packet + 8;
     212             : }
     213             : /* }}} */
     214             : 
     215             : 
     216             : /* {{{ php_mysqlnd_read_error_from_line */
     217             : static enum_func_status
     218         872 : php_mysqlnd_read_error_from_line(zend_uchar *buf, size_t buf_len,
     219             :                                                                 char *error, int error_buf_len,
     220             :                                                                 unsigned int *error_no, char *sqlstate TSRMLS_DC)
     221             : {
     222         872 :         zend_uchar *p = buf;
     223         872 :         int error_msg_len= 0;
     224             : 
     225         872 :         DBG_ENTER("php_mysqlnd_read_error_from_line");
     226             : 
     227         872 :         *error_no = CR_UNKNOWN_ERROR;
     228         872 :         memcpy(sqlstate, unknown_sqlstate, MYSQLND_SQLSTATE_LENGTH);
     229             : 
     230         872 :         if (buf_len > 2) {
     231         872 :                 *error_no = uint2korr(p);
     232         872 :                 p+= 2;
     233             :                 /*
     234             :                   sqlstate is following. No need to check for buf_left_len as we checked > 2 above,
     235             :                   if it was >=2 then we would need a check
     236             :                 */
     237         872 :                 if (*p == '#') {
     238         872 :                         ++p;
     239         872 :                         if ((buf_len - (p - buf)) >= MYSQLND_SQLSTATE_LENGTH) {
     240         872 :                                 memcpy(sqlstate, p, MYSQLND_SQLSTATE_LENGTH);
     241         872 :                                 p+= MYSQLND_SQLSTATE_LENGTH;
     242             :                         } else {
     243           0 :                                 goto end;
     244             :                         }
     245             :                 }
     246         872 :                 if ((buf_len - (p - buf)) > 0) {
     247         872 :                         error_msg_len = MIN((int)((buf_len - (p - buf))), (int) (error_buf_len - 1));
     248         872 :                         memcpy(error, p, error_msg_len);
     249             :                 }
     250             :         }
     251             : end:
     252         872 :         sqlstate[MYSQLND_SQLSTATE_LENGTH] = '\0';
     253         872 :         error[error_msg_len]= '\0';
     254             : 
     255         872 :         DBG_RETURN(FAIL);
     256             : }
     257             : /* }}} */
     258             : 
     259             : 
     260             : /* {{{ mysqlnd_read_header */
     261             : static enum_func_status
     262      286020 : mysqlnd_read_header(MYSQLND_NET * net, MYSQLND_PACKET_HEADER * header,
     263             :                                         MYSQLND_STATS * conn_stats, MYSQLND_ERROR_INFO * error_info TSRMLS_DC)
     264             : {
     265             :         zend_uchar buffer[MYSQLND_HEADER_SIZE];
     266             : 
     267      286020 :         DBG_ENTER(mysqlnd_read_header_name);
     268      286020 :         DBG_INF_FMT("compressed=%u", net->compressed);
     269      286020 :         if (FAIL == net->m.receive_ex(net, buffer, MYSQLND_HEADER_SIZE, conn_stats, error_info TSRMLS_CC)) {
     270           3 :                 DBG_RETURN(FAIL);
     271             :         }
     272             : 
     273      286017 :         header->size = uint3korr(buffer);
     274      286017 :         header->packet_no = uint1korr(buffer + 3);
     275             : 
     276             : #ifdef MYSQLND_DUMP_HEADER_N_BODY
     277      286017 :         DBG_INF_FMT("HEADER: prot_packet_no=%u size=%3u", header->packet_no, header->size);
     278             : #endif
     279      286017 :         MYSQLND_INC_CONN_STATISTIC_W_VALUE2(conn_stats,
     280             :                                                         STAT_PROTOCOL_OVERHEAD_IN, MYSQLND_HEADER_SIZE,
     281             :                                                         STAT_PACKETS_RECEIVED, 1);
     282             : 
     283      286017 :         if (net->compressed || net->packet_no == header->packet_no) {
     284             :                 /*
     285             :                   Have to increase the number, so we can send correct number back. It will
     286             :                   round at 255 as this is unsigned char. The server needs this for simple
     287             :                   flow control checking.
     288             :                 */
     289      286016 :                 net->packet_no++;
     290      286016 :                 DBG_RETURN(PASS);
     291             :         }
     292             : 
     293           3 :         DBG_ERR_FMT("Logical link: packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
     294           2 :                                 net->packet_no, header->packet_no, header->size);
     295             : 
     296           3 :         php_error(E_WARNING, "Packets out of order. Expected %u received %u. Packet size="MYSQLND_SZ_T_SPEC,
     297           2 :                           net->packet_no, header->packet_no, header->size);
     298           1 :         DBG_RETURN(FAIL);
     299             : }
     300             : /* }}} */
     301             : 
     302             : 
     303             : /* {{{ php_mysqlnd_greet_read */
     304             : static enum_func_status
     305        1838 : php_mysqlnd_greet_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
     306             : {
     307             :         zend_uchar buf[2048];
     308        1838 :         zend_uchar *p = buf;
     309        1838 :         zend_uchar *begin = buf;
     310        1838 :         zend_uchar *pad_start = NULL;
     311        1838 :         MYSQLND_PACKET_GREET *packet= (MYSQLND_PACKET_GREET *) _packet;
     312             : 
     313        1838 :         DBG_ENTER("php_mysqlnd_greet_read");
     314             : 
     315        1838 :         PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "greeting", PROT_GREET_PACKET);
     316        1838 :         BAIL_IF_NO_MORE_DATA;
     317             : 
     318        1838 :         packet->auth_plugin_data = packet->intern_auth_plugin_data;
     319        1838 :         packet->auth_plugin_data_len = sizeof(packet->intern_auth_plugin_data);
     320             : 
     321        1838 :         if (packet->header.size < sizeof(buf)) {
     322             :                 /*
     323             :                   Null-terminate the string, so strdup can work even if the packets have a string at the end,
     324             :                   which is not ASCIIZ
     325             :                 */
     326        1838 :                 buf[packet->header.size] = '\0'; 
     327             :         }
     328             : 
     329        1838 :         packet->protocol_version = uint1korr(p);
     330        1838 :         p++;
     331        1838 :         BAIL_IF_NO_MORE_DATA;
     332             : 
     333        1838 :         if (ERROR_MARKER == packet->protocol_version) {
     334           0 :                 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
     335             :                                                                                  packet->error, sizeof(packet->error),
     336             :                                                                                  &packet->error_no, packet->sqlstate
     337             :                                                                                  TSRMLS_CC);
     338             :                 /*
     339             :                   The server doesn't send sqlstate in the greet packet.
     340             :                   It's a bug#26426 , so we have to set it correctly ourselves.
     341             :                   It's probably "Too many connections, which has SQL state 08004".
     342             :                 */
     343           0 :                 if (packet->error_no == 1040) {
     344           0 :                         memcpy(packet->sqlstate, "08004", MYSQLND_SQLSTATE_LENGTH);
     345             :                 }
     346           0 :                 DBG_RETURN(PASS);
     347             :         }
     348             : 
     349        1838 :         packet->server_version = estrdup((char *)p);
     350        1838 :         p+= strlen(packet->server_version) + 1; /* eat the '\0' */
     351        1838 :         BAIL_IF_NO_MORE_DATA;
     352             : 
     353        1838 :         packet->thread_id = uint4korr(p);
     354        1838 :         p+=4;
     355        1838 :         BAIL_IF_NO_MORE_DATA;
     356             : 
     357        1838 :         memcpy(packet->auth_plugin_data, p, SCRAMBLE_LENGTH_323);
     358        1838 :         p+= SCRAMBLE_LENGTH_323;
     359        1838 :         BAIL_IF_NO_MORE_DATA;
     360             : 
     361             :         /* pad1 */
     362        1838 :         p++;
     363        1838 :         BAIL_IF_NO_MORE_DATA;
     364             : 
     365        1838 :         packet->server_capabilities = uint2korr(p);
     366        1838 :         p+= 2;
     367        1838 :         BAIL_IF_NO_MORE_DATA;
     368             : 
     369        1838 :         packet->charset_no = uint1korr(p);
     370        1838 :         p++;
     371        1838 :         BAIL_IF_NO_MORE_DATA;
     372             : 
     373        1838 :         packet->server_status = uint2korr(p);
     374        1838 :         p+= 2;
     375        1838 :         BAIL_IF_NO_MORE_DATA;
     376             : 
     377             :         /* pad2 */
     378        1838 :         pad_start = p;
     379        1838 :         p+= 13;
     380        1838 :         BAIL_IF_NO_MORE_DATA;
     381             : 
     382        1838 :         if ((size_t) (p - buf) < packet->header.size) {
     383             :                 /* auth_plugin_data is split into two parts */
     384        1838 :                 memcpy(packet->auth_plugin_data + SCRAMBLE_LENGTH_323, p, SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323);
     385        1838 :                 p+= SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323;
     386        1838 :                 p++; /* 0x0 at the end of the scramble and thus last byte in the packet in 5.1 and previous */
     387             :         } else {
     388           0 :                 packet->pre41 = TRUE;
     389             :         }
     390             : 
     391             :         /* Is this a 5.5+ server ? */
     392        1838 :         if ((size_t) (p - buf) < packet->header.size) {
     393             :                  /* backtrack one byte, the 0x0 at the end of the scramble in 5.1 and previous */
     394           0 :                 p--;
     395             : 
     396             :         /* Additional 16 bits for server capabilities */
     397           0 :                 packet->server_capabilities |= uint2korr(pad_start) << 16;
     398             :                 /* And a length of the server scramble in one byte */
     399           0 :                 packet->auth_plugin_data_len = uint1korr(pad_start + 2);
     400           0 :                 if (packet->auth_plugin_data_len > SCRAMBLE_LENGTH) {
     401             :                         /* more data*/
     402           0 :                         zend_uchar * new_auth_plugin_data = emalloc(packet->auth_plugin_data_len);
     403           0 :                         if (!new_auth_plugin_data) {
     404           0 :                                 goto premature_end;
     405             :                         }
     406             :                         /* copy what we already have */
     407           0 :                         memcpy(new_auth_plugin_data, packet->auth_plugin_data, SCRAMBLE_LENGTH);
     408             :                         /* add additional scramble data 5.5+ sent us */
     409           0 :                         memcpy(new_auth_plugin_data + SCRAMBLE_LENGTH, p, packet->auth_plugin_data_len - SCRAMBLE_LENGTH);
     410           0 :                         p+= (packet->auth_plugin_data_len - SCRAMBLE_LENGTH);
     411           0 :                         packet->auth_plugin_data = new_auth_plugin_data;
     412             :                 }
     413             :         }
     414             : 
     415        1838 :         if (packet->server_capabilities & CLIENT_PLUGIN_AUTH) {
     416           0 :                 BAIL_IF_NO_MORE_DATA;
     417             :                 /* The server is 5.5.x and supports authentication plugins */
     418           0 :                 packet->auth_protocol = estrdup((char *)p);
     419           0 :                 p+= strlen(packet->auth_protocol) + 1; /* eat the '\0' */
     420             :         }
     421             : 
     422        3676 :         DBG_INF_FMT("proto=%u server=%s thread_id=%u",
     423        1838 :                                 packet->protocol_version, packet->server_version, packet->thread_id);
     424             : 
     425        7352 :         DBG_INF_FMT("server_capabilities=%u charset_no=%u server_status=%i auth_protocol=%s scramble_length=%u",
     426        3676 :                                 packet->server_capabilities, packet->charset_no, packet->server_status,
     427        1838 :                                 packet->auth_protocol? packet->auth_protocol:"n/a", packet->auth_plugin_data_len);
     428             : 
     429        1838 :         DBG_RETURN(PASS);
     430             : premature_end:
     431           0 :         DBG_ERR_FMT("GREET packet %d bytes shorter than expected", p - begin - packet->header.size);
     432           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "GREET packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
     433           0 :                                          p - begin - packet->header.size);
     434           0 :         DBG_RETURN(FAIL);
     435             : }
     436             : /* }}} */
     437             : 
     438             : 
     439             : /* {{{ php_mysqlnd_greet_free_mem */
     440             : static
     441        1852 : void php_mysqlnd_greet_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
     442             : {
     443        1852 :         MYSQLND_PACKET_GREET *p= (MYSQLND_PACKET_GREET *) _packet;
     444        1852 :         if (p->server_version) {
     445        1838 :                 efree(p->server_version);
     446        1838 :                 p->server_version = NULL;
     447             :         }
     448        1852 :         if (p->auth_plugin_data && p->auth_plugin_data != p->intern_auth_plugin_data) {
     449           0 :                 efree(p->auth_plugin_data);
     450           0 :                 p->auth_plugin_data = NULL;
     451             :         }
     452        1852 :         if (p->auth_protocol) {
     453           0 :                 efree(p->auth_protocol);
     454           0 :                 p->auth_protocol = NULL;
     455             :         }
     456        1852 :         if (!stack_allocation) {
     457        1852 :                 mnd_pefree(p, p->header.persistent);
     458             :         }
     459        1852 : }
     460             : /* }}} */
     461             : 
     462             : 
     463             : #define AUTH_WRITE_BUFFER_LEN (MYSQLND_HEADER_SIZE + MYSQLND_MAX_ALLOWED_USER_LEN + SCRAMBLE_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1 + 1024)
     464             : 
     465             : /* {{{ php_mysqlnd_auth_write */
     466             : static
     467        1905 : size_t php_mysqlnd_auth_write(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
     468             : {
     469             :         zend_uchar buffer[AUTH_WRITE_BUFFER_LEN];
     470        1905 :         zend_uchar *p = buffer + MYSQLND_HEADER_SIZE; /* start after the header */
     471             :         int len;
     472        1905 :         MYSQLND_PACKET_AUTH * packet= (MYSQLND_PACKET_AUTH *) _packet;
     473             : 
     474        1905 :         DBG_ENTER("php_mysqlnd_auth_write");
     475             : 
     476        1905 :         if (!packet->is_change_user_packet) {
     477        1838 :                 int4store(p, packet->client_flags);
     478        1838 :                 p+= 4;
     479             : 
     480        1838 :                 int4store(p, packet->max_packet_size);
     481        1838 :                 p+= 4;
     482             : 
     483        1838 :                 int1store(p, packet->charset_no);
     484        1838 :                 p++;
     485             : 
     486        1838 :                 memset(p, 0, 23); /* filler */
     487        1838 :                 p+= 23;
     488             :         }
     489             : 
     490        1905 :         if (packet->send_auth_data || packet->is_change_user_packet) {
     491        1902 :                 len = MIN(strlen(packet->user), MYSQLND_MAX_ALLOWED_USER_LEN);
     492        1902 :                 memcpy(p, packet->user, len);
     493        1902 :                 p+= len;
     494        1902 :                 *p++ = '\0';
     495             : 
     496             :                 /* defensive coding */
     497        1902 :                 if (packet->auth_data == NULL) {
     498          16 :                         packet->auth_data_len = 0;
     499             :                 }
     500        1902 :                 if (packet->auth_data_len > 0xFF) {
     501             :                         const char * const msg = "Authentication data too long. "
     502           0 :                                 "Won't fit into the buffer and will be truncated. Authentication will thus fail";
     503           0 :                         SET_CLIENT_ERROR(*conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, msg);
     504           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", msg);
     505           0 :                         DBG_RETURN(0);
     506             :                 }               
     507             :                 
     508        1902 :                 int1store(p, packet->auth_data_len);
     509        1902 :                 ++p;
     510             : /*!!!!! is the buffer big enough ??? */
     511        1902 :                 if ((sizeof(buffer) - (p - buffer)) < packet->auth_data_len) {
     512           0 :                         DBG_ERR("the stack buffer was not enough!!");
     513           0 :                         DBG_RETURN(0);
     514             :                 }
     515        1902 :                 if (packet->auth_data_len) {
     516        1886 :                         memcpy(p, packet->auth_data, packet->auth_data_len);
     517        1886 :                         p+= packet->auth_data_len;
     518             :                 }
     519             : 
     520        1902 :                 if (packet->db) {
     521             :                         /* CLIENT_CONNECT_WITH_DB should have been set */
     522        1902 :                         size_t real_db_len = MIN(MYSQLND_MAX_ALLOWED_DB_LEN, packet->db_len);
     523        1902 :                         memcpy(p, packet->db, real_db_len);
     524        1902 :                         p+= real_db_len;
     525        1902 :                         *p++= '\0';
     526           0 :                 } else if (packet->is_change_user_packet) {
     527           0 :                         *p++= '\0';             
     528             :                 }
     529             :                 /* no \0 for no DB */
     530             : 
     531        1902 :                 if (packet->is_change_user_packet) {
     532          67 :                         if (packet->charset_no) {
     533          67 :                                 int2store(p, packet->charset_no);
     534          67 :                                 p+= 2;
     535             :                         }
     536             :                 }
     537             :                 
     538        1902 :                 if (packet->auth_plugin_name) {
     539        1902 :                         size_t len = MIN(strlen(packet->auth_plugin_name), sizeof(buffer) - (p - buffer) - 1);
     540        1902 :                         memcpy(p, packet->auth_plugin_name, len);
     541        1902 :                         p+= len;
     542        1902 :                         *p++= '\0';
     543             :                 }
     544             :         }
     545        1905 :         if (packet->is_change_user_packet) {
     546         134 :                 if (PASS != conn->m->simple_command(conn, COM_CHANGE_USER, buffer + MYSQLND_HEADER_SIZE, p - buffer - MYSQLND_HEADER_SIZE,
     547             :                                                                                    PROT_LAST /* the caller will handle the OK packet */,
     548          67 :                                                                                    packet->silent, TRUE TSRMLS_CC)) {
     549           1 :                         DBG_RETURN(0);
     550             :                 }
     551          66 :                 DBG_RETURN(p - buffer - MYSQLND_HEADER_SIZE);
     552             :         } else {
     553        1838 :                 size_t sent = conn->net->m.send_ex(conn->net, buffer, p - buffer - MYSQLND_HEADER_SIZE, conn->stats, conn->error_info TSRMLS_CC);
     554        1838 :                 if (!sent) {
     555           0 :                         CONN_SET_STATE(conn, CONN_QUIT_SENT);
     556             :                 }
     557        1838 :                 DBG_RETURN(sent);
     558             :         }
     559             : }
     560             : /* }}} */
     561             : 
     562             : 
     563             : /* {{{ php_mysqlnd_auth_free_mem */
     564             : static
     565        3740 : void php_mysqlnd_auth_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
     566             : {
     567        3740 :         if (!stack_allocation) {
     568        3740 :                 MYSQLND_PACKET_AUTH * p = (MYSQLND_PACKET_AUTH *) _packet;
     569        3740 :                 mnd_pefree(p, p->header.persistent);
     570             :         }
     571        3740 : }
     572             : /* }}} */
     573             : 
     574             : 
     575             : #define AUTH_RESP_BUFFER_SIZE 2048
     576             : 
     577             : /* {{{ php_mysqlnd_auth_response_read */
     578             : static enum_func_status
     579        1835 : php_mysqlnd_auth_response_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
     580             : {
     581             :         zend_uchar local_buf[AUTH_RESP_BUFFER_SIZE];
     582        1835 :         size_t buf_len = conn->net->cmd_buffer.buffer? conn->net->cmd_buffer.length: AUTH_RESP_BUFFER_SIZE;
     583        1835 :         zend_uchar *buf = conn->net->cmd_buffer.buffer? (zend_uchar *) conn->net->cmd_buffer.buffer : local_buf;
     584        1835 :         zend_uchar *p = buf;
     585        1835 :         zend_uchar *begin = buf;
     586             :         unsigned long i;
     587        1835 :         register MYSQLND_PACKET_AUTH_RESPONSE * packet= (MYSQLND_PACKET_AUTH_RESPONSE *) _packet;
     588             : 
     589        1835 :         DBG_ENTER("php_mysqlnd_auth_response_read");
     590             : 
     591             :         /* leave space for terminating safety \0 */
     592        1835 :         buf_len--;
     593        1835 :         PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "OK", PROT_OK_PACKET);
     594        1835 :         BAIL_IF_NO_MORE_DATA;
     595             : 
     596             :         /*
     597             :           zero-terminate the buffer for safety. We are sure there is place for the \0
     598             :           because buf_len is -1 the size of the buffer pointed
     599             :         */
     600        1835 :         buf[packet->header.size] = '\0';
     601             :         
     602             :         /* Should be always 0x0 or ERROR_MARKER for error */
     603        1835 :         packet->response_code = uint1korr(p);
     604        1835 :         p++;
     605        1835 :         BAIL_IF_NO_MORE_DATA;
     606             : 
     607        1835 :         if (ERROR_MARKER == packet->response_code) {
     608          34 :                 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
     609             :                                                                                  packet->error, sizeof(packet->error),
     610             :                                                                                  &packet->error_no, packet->sqlstate
     611             :                                                                                  TSRMLS_CC);
     612          34 :                 DBG_RETURN(PASS);
     613             :         }
     614        1801 :         if (0xFE == packet->response_code) {
     615             :                 /* Authentication Switch Response */
     616           0 :                 if (packet->header.size > (size_t) (p - buf)) {
     617           0 :                         packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE);
     618           0 :                         packet->new_auth_protocol_len = strlen(packet->new_auth_protocol);
     619           0 :                         p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */
     620             : 
     621           0 :                         packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf);
     622           0 :                         if (packet->new_auth_protocol_data_len) {
     623           0 :                                 packet->new_auth_protocol_data = mnd_emalloc(packet->new_auth_protocol_data_len);
     624           0 :                                 memcpy(packet->new_auth_protocol_data, p, packet->new_auth_protocol_data_len);
     625             :                         }
     626           0 :                         DBG_INF_FMT("The server requested switching auth plugin to : %s", packet->new_auth_protocol);
     627           0 :                         DBG_INF_FMT("Server salt : [%*s]", packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
     628             :                 }
     629             :         } else {
     630             :                 /* Everything was fine! */
     631        1801 :                 packet->affected_rows  = php_mysqlnd_net_field_length_ll(&p);
     632        1801 :                 BAIL_IF_NO_MORE_DATA;
     633             : 
     634        1801 :                 packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p);
     635        1801 :                 BAIL_IF_NO_MORE_DATA;
     636             : 
     637        1801 :                 packet->server_status = uint2korr(p);
     638        1801 :                 p+= 2;
     639        1801 :                 BAIL_IF_NO_MORE_DATA;
     640             : 
     641        1801 :                 packet->warning_count = uint2korr(p);
     642        1801 :                 p+= 2;
     643        1801 :                 BAIL_IF_NO_MORE_DATA;
     644             : 
     645             :                 /* There is a message */
     646        1801 :                 if (packet->header.size > (size_t) (p - buf) && (i = php_mysqlnd_net_field_length(&p))) {
     647           0 :                         packet->message_len = MIN(i, buf_len - (p - begin));
     648           0 :                         packet->message = mnd_pestrndup((char *)p, packet->message_len, FALSE);
     649             :                 } else {
     650        1801 :                         packet->message = NULL;
     651        1801 :                         packet->message_len = 0;
     652             :                 }
     653             : 
     654        3602 :                 DBG_INF_FMT("OK packet: aff_rows=%lld last_ins_id=%ld server_status=%u warnings=%u",
     655        1801 :                                         packet->affected_rows, packet->last_insert_id, packet->server_status,
     656        1801 :                                         packet->warning_count);
     657             :         }
     658             : 
     659        1801 :         DBG_RETURN(PASS);
     660             : premature_end:
     661           0 :         DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size);
     662           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "AUTH_RESPONSE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
     663           0 :                                          p - begin - packet->header.size);
     664           0 :         DBG_RETURN(FAIL);
     665             : }
     666             : /* }}} */
     667             : 
     668             : 
     669             : /* {{{ php_mysqlnd_auth_response_free_mem */
     670             : static void
     671        1835 : php_mysqlnd_auth_response_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
     672             : {
     673        1835 :         MYSQLND_PACKET_AUTH_RESPONSE * p = (MYSQLND_PACKET_AUTH_RESPONSE *) _packet;
     674        1835 :         if (p->message) {
     675           0 :                 mnd_efree(p->message);
     676           0 :                 p->message = NULL;
     677             :         }
     678        1835 :         if (p->new_auth_protocol) {
     679           0 :                 mnd_efree(p->new_auth_protocol);
     680           0 :                 p->new_auth_protocol = NULL;
     681             :         }
     682        1835 :         p->new_auth_protocol_len = 0;
     683             : 
     684        1835 :         if (p->new_auth_protocol_data) {
     685           0 :                 mnd_efree(p->new_auth_protocol_data);
     686           0 :                 p->new_auth_protocol_data = NULL;
     687             :         }
     688        1835 :         p->new_auth_protocol_data_len = 0;
     689             : 
     690        1835 :         if (!stack_allocation) {
     691        1835 :                 mnd_pefree(p, p->header.persistent);
     692             :         }
     693        1835 : }
     694             : /* }}} */
     695             : 
     696             : 
     697             : /* {{{ php_mysqlnd_change_auth_response_write */
     698             : static size_t
     699           0 : php_mysqlnd_change_auth_response_write(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
     700             : {
     701           0 :         MYSQLND_PACKET_CHANGE_AUTH_RESPONSE *packet= (MYSQLND_PACKET_CHANGE_AUTH_RESPONSE *) _packet;
     702           0 :         zend_uchar * buffer = conn->net->cmd_buffer.length >= packet->auth_data_len? conn->net->cmd_buffer.buffer : mnd_emalloc(packet->auth_data_len);
     703           0 :         zend_uchar *p = buffer + MYSQLND_HEADER_SIZE; /* start after the header */
     704             : 
     705           0 :         DBG_ENTER("php_mysqlnd_change_auth_response_write");
     706             : 
     707           0 :         if (packet->auth_data_len) {
     708           0 :                 memcpy(p, packet->auth_data, packet->auth_data_len);
     709           0 :                 p+= packet->auth_data_len;
     710             :         }
     711             : 
     712             :         {
     713           0 :                 size_t sent = conn->net->m.send_ex(conn->net, buffer, p - buffer - MYSQLND_HEADER_SIZE, conn->stats, conn->error_info TSRMLS_CC);
     714           0 :                 if (buffer != conn->net->cmd_buffer.buffer) {
     715           0 :                         mnd_efree(buffer);
     716             :                 }
     717           0 :                 if (!sent) {
     718           0 :                         CONN_SET_STATE(conn, CONN_QUIT_SENT);
     719             :                 }
     720           0 :                 DBG_RETURN(sent);
     721             :         }
     722             : }
     723             : /* }}} */
     724             : 
     725             : 
     726             : /* {{{ php_mysqlnd_change_auth_response_free_mem */
     727             : static void
     728           0 : php_mysqlnd_change_auth_response_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
     729             : {
     730           0 :         if (!stack_allocation) {
     731           0 :                 MYSQLND_PACKET_CHANGE_AUTH_RESPONSE * p = (MYSQLND_PACKET_CHANGE_AUTH_RESPONSE *) _packet;
     732           0 :                 mnd_pefree(p, p->header.persistent);
     733             :         }
     734           0 : }
     735             : /* }}} */
     736             : 
     737             : 
     738             : #define OK_BUFFER_SIZE 2048
     739             : 
     740             : /* {{{ php_mysqlnd_ok_read */
     741             : static enum_func_status
     742         302 : php_mysqlnd_ok_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
     743             : {
     744             :         zend_uchar local_buf[OK_BUFFER_SIZE];
     745         302 :         size_t buf_len = conn->net->cmd_buffer.buffer? conn->net->cmd_buffer.length : OK_BUFFER_SIZE;
     746         302 :         zend_uchar *buf = conn->net->cmd_buffer.buffer? (zend_uchar *) conn->net->cmd_buffer.buffer : local_buf;
     747         302 :         zend_uchar *p = buf;
     748         302 :         zend_uchar *begin = buf;
     749             :         unsigned long i;
     750         302 :         register MYSQLND_PACKET_OK *packet= (MYSQLND_PACKET_OK *) _packet;
     751             : 
     752         302 :         DBG_ENTER("php_mysqlnd_ok_read");
     753             : 
     754         302 :         PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "OK", PROT_OK_PACKET);
     755         302 :         BAIL_IF_NO_MORE_DATA;
     756             : 
     757             :         /* Should be always 0x0 or ERROR_MARKER for error */
     758         302 :         packet->field_count = uint1korr(p);
     759         302 :         p++;
     760         302 :         BAIL_IF_NO_MORE_DATA;
     761             : 
     762         302 :         if (ERROR_MARKER == packet->field_count) {
     763          10 :                 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
     764             :                                                                                  packet->error, sizeof(packet->error),
     765             :                                                                                  &packet->error_no, packet->sqlstate
     766             :                                                                                  TSRMLS_CC);
     767          10 :                 DBG_INF_FMT("conn->server_status=%u", conn->upsert_status->server_status);
     768          10 :                 DBG_RETURN(PASS);
     769             :         }
     770             :         /* Everything was fine! */
     771         292 :         packet->affected_rows  = php_mysqlnd_net_field_length_ll(&p);
     772         292 :         BAIL_IF_NO_MORE_DATA;
     773             : 
     774         292 :         packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p);
     775         292 :         BAIL_IF_NO_MORE_DATA;
     776             : 
     777         292 :         packet->server_status = uint2korr(p);
     778         292 :         p+= 2;
     779         292 :         BAIL_IF_NO_MORE_DATA;
     780             : 
     781         292 :         packet->warning_count = uint2korr(p);
     782         292 :         p+= 2;
     783         292 :         BAIL_IF_NO_MORE_DATA;
     784             : 
     785             :         /* There is a message */
     786         305 :         if (packet->header.size > (size_t) (p - buf) && (i = php_mysqlnd_net_field_length(&p))) {
     787          13 :                 packet->message_len = MIN(i, buf_len - (p - begin));
     788          13 :                 packet->message = mnd_pestrndup((char *)p, packet->message_len, FALSE);
     789             :         } else {
     790         279 :                 packet->message = NULL;
     791         279 :                 packet->message_len = 0;
     792             :         }
     793             : 
     794         584 :         DBG_INF_FMT("OK packet: aff_rows=%lld last_ins_id=%ld server_status=%u warnings=%u",
     795         292 :                                 packet->affected_rows, packet->last_insert_id, packet->server_status,
     796         292 :                                 packet->warning_count);
     797             : 
     798         292 :         BAIL_IF_NO_MORE_DATA;
     799             : 
     800         292 :         DBG_RETURN(PASS);
     801             : premature_end:
     802           0 :         DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size);
     803           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "OK packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
     804           0 :                                          p - begin - packet->header.size);
     805           0 :         DBG_RETURN(FAIL);
     806             : }
     807             : /* }}} */
     808             : 
     809             : 
     810             : /* {{{ php_mysqlnd_ok_free_mem */
     811             : static void
     812         302 : php_mysqlnd_ok_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
     813             : {
     814         302 :         MYSQLND_PACKET_OK *p= (MYSQLND_PACKET_OK *) _packet;
     815         302 :         if (p->message) {
     816          13 :                 mnd_efree(p->message);
     817          13 :                 p->message = NULL;
     818             :         }
     819         302 :         if (!stack_allocation) {
     820         302 :                 mnd_pefree(p, p->header.persistent);
     821             :         }
     822         302 : }
     823             : /* }}} */
     824             : 
     825             : 
     826             : /* {{{ php_mysqlnd_eof_read */
     827             : static enum_func_status
     828        8018 : php_mysqlnd_eof_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
     829             : {
     830             :         /*
     831             :           EOF packet is since 4.1 five bytes long,
     832             :           but we can get also an error, make it bigger.
     833             : 
     834             :           Error : error_code + '#' + sqlstate + MYSQLND_ERRMSG_SIZE
     835             :         */
     836        8018 :         MYSQLND_PACKET_EOF *packet= (MYSQLND_PACKET_EOF *) _packet;
     837        8018 :         size_t buf_len = conn->net->cmd_buffer.length;
     838        8018 :         zend_uchar *buf = (zend_uchar *) conn->net->cmd_buffer.buffer;
     839        8018 :         zend_uchar *p = buf;
     840        8018 :         zend_uchar *begin = buf;
     841             : 
     842        8018 :         DBG_ENTER("php_mysqlnd_eof_read");
     843             : 
     844        8018 :         PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "EOF", PROT_EOF_PACKET);
     845        8018 :         BAIL_IF_NO_MORE_DATA;
     846             : 
     847             :         /* Should be always EODATA_MARKER */
     848        8018 :         packet->field_count = uint1korr(p);
     849        8018 :         p++;
     850        8018 :         BAIL_IF_NO_MORE_DATA;
     851             : 
     852        8018 :         if (ERROR_MARKER == packet->field_count) {
     853           2 :                 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
     854             :                                                                                  packet->error, sizeof(packet->error),
     855             :                                                                                  &packet->error_no, packet->sqlstate
     856             :                                                                                  TSRMLS_CC);
     857           2 :                 DBG_RETURN(PASS);
     858             :         }
     859             : 
     860             :         /*
     861             :                 4.1 sends 1 byte EOF packet after metadata of
     862             :                 PREPARE/EXECUTE but 5 bytes after the result. This is not
     863             :                 according to the Docs@Forge!!!
     864             :         */
     865        8016 :         if (packet->header.size > 1) {
     866        8016 :                 packet->warning_count = uint2korr(p);
     867        8016 :                 p+= 2;
     868        8016 :                 BAIL_IF_NO_MORE_DATA;
     869             : 
     870        8016 :                 packet->server_status = uint2korr(p);
     871        8016 :                 p+= 2;
     872        8016 :                 BAIL_IF_NO_MORE_DATA;
     873             :         } else {
     874           0 :                 packet->warning_count = 0;
     875           0 :                 packet->server_status = 0;
     876             :         }
     877             : 
     878        8016 :         BAIL_IF_NO_MORE_DATA;
     879             : 
     880       24048 :         DBG_INF_FMT("EOF packet: fields=%u status=%u warnings=%u",
     881       24048 :                                 packet->field_count, packet->server_status, packet->warning_count);
     882             : 
     883        8016 :         DBG_RETURN(PASS);
     884             : premature_end:
     885           0 :         DBG_ERR_FMT("EOF packet %d bytes shorter than expected", p - begin - packet->header.size);
     886           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "EOF packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
     887           0 :                                          p - begin - packet->header.size);
     888           0 :         DBG_RETURN(FAIL);
     889             : }
     890             : /* }}} */
     891             : 
     892             : 
     893             : /* {{{ php_mysqlnd_eof_free_mem */
     894             : static
     895        8018 : void php_mysqlnd_eof_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
     896             : {
     897        8018 :         if (!stack_allocation) {
     898        8018 :                 mnd_pefree(_packet, ((MYSQLND_PACKET_EOF *)_packet)->header.persistent);
     899             :         }
     900        8018 : }
     901             : /* }}} */
     902             : 
     903             : 
     904             : /* {{{ php_mysqlnd_cmd_write */
     905       36624 : size_t php_mysqlnd_cmd_write(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
     906             : {
     907             :         /* Let's have some space, which we can use, if not enough, we will allocate new buffer */
     908       36624 :         MYSQLND_PACKET_COMMAND * packet= (MYSQLND_PACKET_COMMAND *) _packet;
     909       36624 :         MYSQLND_NET * net = conn->net;
     910       36624 :         unsigned int error_reporting = EG(error_reporting);
     911       36624 :         size_t sent = 0;
     912             : 
     913       36624 :         DBG_ENTER("php_mysqlnd_cmd_write");
     914             :         /*
     915             :           Reset packet_no, or we will get bad handshake!
     916             :           Every command starts a new TX and packet numbers are reset to 0.
     917             :         */
     918       36624 :         net->packet_no = 0;
     919       36624 :         net->compressed_envelope_packet_no = 0; /* this is for the response */
     920             : 
     921       36624 :         if (error_reporting) {
     922       36046 :                 EG(error_reporting) = 0;
     923             :         }
     924             : 
     925       36624 :         MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_PACKETS_SENT_CMD);
     926             : 
     927             : #ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
     928             :         net->m.consume_uneaten_data(net, packet->command TSRMLS_CC);
     929             : #endif
     930             : 
     931       38464 :         if (!packet->argument || !packet->arg_len) {
     932             :                 zend_uchar buffer[MYSQLND_HEADER_SIZE + 1];
     933             : 
     934        1840 :                 int1store(buffer + MYSQLND_HEADER_SIZE, packet->command);
     935        1840 :                 sent = net->m.send_ex(net, buffer, 1, conn->stats, conn->error_info TSRMLS_CC);
     936             :         } else {
     937       34784 :                 size_t tmp_len = packet->arg_len + 1 + MYSQLND_HEADER_SIZE;
     938             :                 zend_uchar *tmp, *p;
     939       34784 :                 tmp = (tmp_len > net->cmd_buffer.length)? mnd_emalloc(tmp_len):net->cmd_buffer.buffer;
     940       34784 :                 if (!tmp) {
     941           0 :                         goto end;
     942             :                 }
     943       34784 :                 p = tmp + MYSQLND_HEADER_SIZE; /* skip the header */
     944             : 
     945       34784 :                 int1store(p, packet->command);
     946       34784 :                 p++;
     947             : 
     948       34784 :                 memcpy(p, packet->argument, packet->arg_len);
     949             : 
     950       34784 :                 sent = net->m.send_ex(net, tmp, tmp_len - MYSQLND_HEADER_SIZE, conn->stats, conn->error_info TSRMLS_CC);
     951       34784 :                 if (tmp != net->cmd_buffer.buffer) {
     952          39 :                         MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CMD_BUFFER_TOO_SMALL);
     953          39 :                         mnd_efree(tmp);
     954             :                 }
     955             :         }
     956             : end:
     957       36624 :         if (error_reporting) {
     958             :                 /* restore error reporting */
     959       36046 :                 EG(error_reporting) = error_reporting;
     960             :         }
     961       36624 :         if (!sent) {
     962          12 :                 CONN_SET_STATE(conn, CONN_QUIT_SENT);
     963             :         }
     964       36624 :         DBG_RETURN(sent);
     965             : }
     966             : /* }}} */
     967             : 
     968             : 
     969             : /* {{{ php_mysqlnd_cmd_free_mem */
     970             : static
     971       36624 : void php_mysqlnd_cmd_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
     972             : {
     973       36624 :         if (!stack_allocation) {
     974       36624 :                 MYSQLND_PACKET_COMMAND * p = (MYSQLND_PACKET_COMMAND *) _packet;
     975       36624 :                 mnd_pefree(p, p->header.persistent);
     976             :         }
     977       36624 : }
     978             : /* }}} */
     979             : 
     980             : 
     981             : /* {{{ php_mysqlnd_rset_header_read */
     982             : static enum_func_status
     983       25935 : php_mysqlnd_rset_header_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
     984             : {
     985       25935 :         enum_func_status ret = PASS;
     986       25935 :         size_t buf_len = conn->net->cmd_buffer.length;
     987       25935 :         zend_uchar *buf = (zend_uchar *) conn->net->cmd_buffer.buffer;
     988       25935 :         zend_uchar *p = buf;
     989       25935 :         zend_uchar *begin = buf;
     990             :         size_t len;
     991       25935 :         MYSQLND_PACKET_RSET_HEADER *packet= (MYSQLND_PACKET_RSET_HEADER *) _packet;
     992             : 
     993       25935 :         DBG_ENTER("php_mysqlnd_rset_header_read");
     994             : 
     995       25935 :         PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "resultset header", PROT_RSET_HEADER_PACKET);
     996       25934 :         BAIL_IF_NO_MORE_DATA;
     997             : 
     998             :         /*
     999             :           Don't increment. First byte is ERROR_MARKER on error, but otherwise is starting byte
    1000             :           of encoded sequence for length.
    1001             :         */
    1002       25934 :         if (ERROR_MARKER == *p) {
    1003             :                 /* Error */
    1004         787 :                 p++;
    1005         787 :                 BAIL_IF_NO_MORE_DATA;
    1006         787 :                 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
    1007             :                                                                                  packet->error_info.error, sizeof(packet->error_info.error),
    1008             :                                                                                  &packet->error_info.error_no, packet->error_info.sqlstate
    1009             :                                                                                  TSRMLS_CC);
    1010         787 :                 DBG_INF_FMT("conn->server_status=%u", conn->upsert_status->server_status);
    1011         787 :                 DBG_RETURN(PASS);
    1012             :         }
    1013             : 
    1014       25147 :         packet->field_count = php_mysqlnd_net_field_length(&p);
    1015       25147 :         BAIL_IF_NO_MORE_DATA;
    1016             : 
    1017       25146 :         switch (packet->field_count) {
    1018             :                 case MYSQLND_NULL_LENGTH:
    1019          13 :                         DBG_INF("LOAD LOCAL");
    1020             :                         /*
    1021             :                           First byte in the packet is the field count.
    1022             :                           Thus, the name is size - 1. And we add 1 for a trailing \0.
    1023             :                           Because we have BAIL_IF_NO_MORE_DATA before the switch, we are guaranteed
    1024             :                           that packet->header.size is > 0. Which means that len can't underflow, that
    1025             :                           would lead to 0 byte allocation but 2^32 or 2^64 bytes copied.
    1026             :                         */
    1027          13 :                         len = packet->header.size - 1;
    1028          13 :                         packet->info_or_local_file = mnd_emalloc(len + 1);
    1029          13 :                         if (packet->info_or_local_file) {
    1030          13 :                                 memcpy(packet->info_or_local_file, p, len);
    1031          13 :                                 packet->info_or_local_file[len] = '\0';
    1032          13 :                                 packet->info_or_local_file_len = len;
    1033             :                         } else {
    1034           0 :                                 SET_OOM_ERROR(*conn->error_info);
    1035           0 :                                 ret = FAIL;     
    1036             :                         }
    1037          13 :                         break;
    1038             :                 case 0x00:
    1039       20503 :                         DBG_INF("UPSERT");
    1040       20503 :                         packet->affected_rows = php_mysqlnd_net_field_length_ll(&p);
    1041       20503 :                         BAIL_IF_NO_MORE_DATA;
    1042             : 
    1043       20503 :                         packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p);
    1044       20503 :                         BAIL_IF_NO_MORE_DATA;
    1045             : 
    1046       20503 :                         packet->server_status = uint2korr(p);
    1047       20503 :                         p+=2;
    1048       20503 :                         BAIL_IF_NO_MORE_DATA;
    1049             : 
    1050       20503 :                         packet->warning_count = uint2korr(p);
    1051       20503 :                         p+=2;
    1052       20503 :                         BAIL_IF_NO_MORE_DATA;
    1053             :                         /* Check for additional textual data */
    1054       20503 :                         if (packet->header.size  > (size_t) (p - buf) && (len = php_mysqlnd_net_field_length(&p))) {
    1055         396 :                                 packet->info_or_local_file = mnd_emalloc(len + 1);
    1056         396 :                                 if (packet->info_or_local_file) {
    1057         396 :                                         memcpy(packet->info_or_local_file, p, len);
    1058         396 :                                         packet->info_or_local_file[len] = '\0';
    1059         396 :                                         packet->info_or_local_file_len = len;
    1060             :                                 } else {
    1061           0 :                                         SET_OOM_ERROR(*conn->error_info);
    1062           0 :                                         ret = FAIL;
    1063             :                                 }
    1064             :                         }
    1065       41006 :                         DBG_INF_FMT("affected_rows=%llu last_insert_id=%llu server_status=%u warning_count=%u",
    1066             :                                                 packet->affected_rows, packet->last_insert_id,
    1067       41006 :                                                 packet->server_status, packet->warning_count);
    1068       20503 :                         break;
    1069             :                 default:
    1070        4630 :                         DBG_INF("SELECT");
    1071             :                         /* Result set */
    1072             :                         break;
    1073             :         }
    1074       25146 :         BAIL_IF_NO_MORE_DATA;
    1075             : 
    1076       25146 :         DBG_RETURN(ret);
    1077             : premature_end:
    1078           1 :         DBG_ERR_FMT("RSET_HEADER packet %d bytes shorter than expected", p - begin - packet->header.size);
    1079           1 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "RSET_HEADER packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
    1080           1 :                                          p - begin - packet->header.size);
    1081           1 :         DBG_RETURN(FAIL);
    1082             : }
    1083             : /* }}} */
    1084             : 
    1085             : 
    1086             : /* {{{ php_mysqlnd_rset_header_free_mem */
    1087             : static
    1088       25935 : void php_mysqlnd_rset_header_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
    1089             : {
    1090       25935 :         MYSQLND_PACKET_RSET_HEADER *p= (MYSQLND_PACKET_RSET_HEADER *) _packet;
    1091       25935 :         DBG_ENTER("php_mysqlnd_rset_header_free_mem");
    1092       25935 :         if (p->info_or_local_file) {
    1093         409 :                 mnd_efree(p->info_or_local_file);
    1094         409 :                 p->info_or_local_file = NULL;
    1095             :         }
    1096       25935 :         if (!stack_allocation) {
    1097       25935 :                 mnd_pefree(p, p->header.persistent);
    1098             :         }
    1099       25935 :         DBG_VOID_RETURN;
    1100             : }
    1101             : /* }}} */
    1102             : 
    1103             : static size_t rset_field_offsets[] =
    1104             : {
    1105             :         STRUCT_OFFSET(MYSQLND_FIELD, catalog),
    1106             :         STRUCT_OFFSET(MYSQLND_FIELD, catalog_length),
    1107             :         STRUCT_OFFSET(MYSQLND_FIELD, db),
    1108             :         STRUCT_OFFSET(MYSQLND_FIELD, db_length),
    1109             :         STRUCT_OFFSET(MYSQLND_FIELD, table),
    1110             :         STRUCT_OFFSET(MYSQLND_FIELD, table_length),
    1111             :         STRUCT_OFFSET(MYSQLND_FIELD, org_table),
    1112             :         STRUCT_OFFSET(MYSQLND_FIELD, org_table_length),
    1113             :         STRUCT_OFFSET(MYSQLND_FIELD, name),
    1114             :         STRUCT_OFFSET(MYSQLND_FIELD, name_length),
    1115             :         STRUCT_OFFSET(MYSQLND_FIELD, org_name),
    1116             :         STRUCT_OFFSET(MYSQLND_FIELD, org_name_length)
    1117             : };
    1118             : 
    1119             : 
    1120             : /* {{{ php_mysqlnd_rset_field_read */
    1121             : static enum_func_status
    1122      158214 : php_mysqlnd_rset_field_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
    1123             : {
    1124             :         /* Should be enough for the metadata of a single row */
    1125      158214 :         MYSQLND_PACKET_RES_FIELD *packet= (MYSQLND_PACKET_RES_FIELD *) _packet;
    1126      158214 :         size_t buf_len = conn->net->cmd_buffer.length, total_len = 0;
    1127      158214 :         zend_uchar *buf = (zend_uchar *) conn->net->cmd_buffer.buffer;
    1128      158214 :         zend_uchar *p = buf;
    1129      158214 :         zend_uchar *begin = buf;
    1130             :         char *root_ptr;
    1131             :         unsigned long len;
    1132             :         MYSQLND_FIELD *meta;
    1133      158214 :         unsigned int i, field_count = sizeof(rset_field_offsets)/sizeof(size_t);
    1134             : 
    1135      158214 :         DBG_ENTER("php_mysqlnd_rset_field_read");
    1136             : 
    1137      158214 :         PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "field", PROT_RSET_FLD_PACKET);
    1138             : 
    1139      158214 :         if (packet->skip_parsing) {
    1140      134414 :                 DBG_RETURN(PASS);
    1141             :         }
    1142             : 
    1143       23800 :         BAIL_IF_NO_MORE_DATA;
    1144       23800 :         if (ERROR_MARKER == *p) {
    1145             :                 /* Error */
    1146           1 :                 p++;
    1147           1 :                 BAIL_IF_NO_MORE_DATA;
    1148           1 :                 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
    1149             :                                                                                  packet->error_info.error, sizeof(packet->error_info.error),
    1150             :                                                                                  &packet->error_info.error_no, packet->error_info.sqlstate
    1151             :                                                                                  TSRMLS_CC);
    1152           1 :                 DBG_ERR_FMT("Server error : (%u) %s", packet->error_info.error_no, packet->error_info.error);
    1153           1 :                 DBG_RETURN(PASS);
    1154       23799 :         } else if (EODATA_MARKER == *p && packet->header.size < 8) {
    1155             :                 /* Premature EOF. That should be COM_FIELD_LIST */
    1156           3 :                 DBG_INF("Premature EOF. That should be COM_FIELD_LIST");
    1157           3 :                 packet->stupid_list_fields_eof = TRUE;
    1158           3 :                 DBG_RETURN(PASS);
    1159             :         }
    1160             : 
    1161       23796 :         meta = packet->metadata;
    1162             : 
    1163      166572 :         for (i = 0; i < field_count; i += 2) {
    1164      142776 :                 len = php_mysqlnd_net_field_length(&p);
    1165      142776 :                 BAIL_IF_NO_MORE_DATA;
    1166      142776 :                 switch ((len)) {
    1167             :                         case 0:
    1168       23663 :                                 *(const char **)(((char*)meta) + rset_field_offsets[i]) = mysqlnd_empty_string;
    1169       23663 :                                 *(unsigned int *)(((char*)meta) + rset_field_offsets[i+1]) = 0;
    1170       23663 :                                 break;
    1171             :                         case MYSQLND_NULL_LENGTH:
    1172           0 :                                 goto faulty_or_fake;
    1173             :                         default:
    1174      119113 :                                 *(const char **)(((char *)meta) + rset_field_offsets[i]) = (const char *)p;
    1175      119113 :                                 *(unsigned int *)(((char*)meta) + rset_field_offsets[i+1]) = len;
    1176      119113 :                                 p += len;
    1177      119113 :                                 total_len += len + 1;
    1178             :                                 break;
    1179             :                 }
    1180      142776 :                 BAIL_IF_NO_MORE_DATA;
    1181             :         }
    1182             : 
    1183             :         /* 1 byte length */
    1184       23796 :         if (12 != *p) {
    1185           0 :                 DBG_ERR_FMT("Protocol error. Server sent false length. Expected 12 got %d", (int) *p);
    1186           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Protocol error. Server sent false length. Expected 12");
    1187             :         }
    1188       23796 :         p++;
    1189       23796 :         BAIL_IF_NO_MORE_DATA;
    1190             : 
    1191       23796 :         meta->charsetnr = uint2korr(p);
    1192       23796 :         p += 2;
    1193       23796 :         BAIL_IF_NO_MORE_DATA;
    1194             : 
    1195       23796 :         meta->length = uint4korr(p);
    1196       23796 :         p += 4;
    1197       23796 :         BAIL_IF_NO_MORE_DATA;
    1198             : 
    1199       23796 :         meta->type = uint1korr(p);
    1200       23796 :         p += 1;
    1201       23796 :         BAIL_IF_NO_MORE_DATA;
    1202             : 
    1203       23796 :         meta->flags = uint2korr(p);
    1204       23796 :         p += 2;
    1205       23796 :         BAIL_IF_NO_MORE_DATA;
    1206             : 
    1207       23796 :         meta->decimals = uint1korr(p);
    1208       23796 :         p += 1;
    1209       23796 :         BAIL_IF_NO_MORE_DATA;
    1210             : 
    1211             :         /* 2 byte filler */
    1212       23796 :         p +=2;
    1213       23796 :         BAIL_IF_NO_MORE_DATA;
    1214             : 
    1215             :         /* Should we set NUM_FLAG (libmysql does it) ? */
    1216       47820 :         if (
    1217       23796 :                 (meta->type <= MYSQL_TYPE_INT24 &&
    1218       10892 :                         (meta->type != MYSQL_TYPE_TIMESTAMP || meta->length == 14 || meta->length == 8)
    1219       13132 :                 ) || meta->type == MYSQL_TYPE_YEAR)
    1220             :         {
    1221       10711 :                 meta->flags |= NUM_FLAG;
    1222             :         }
    1223             : 
    1224             : 
    1225             :         /*
    1226             :           def could be empty, thus don't allocate on the root.
    1227             :           NULL_LENGTH (0xFB) comes from COM_FIELD_LIST when the default value is NULL.
    1228             :           Otherwise the string is length encoded.
    1229             :         */
    1230       23801 :         if (packet->header.size > (size_t) (p - buf) &&
    1231           5 :                 (len = php_mysqlnd_net_field_length(&p)) &&
    1232             :                 len != MYSQLND_NULL_LENGTH)
    1233             :         {
    1234           3 :                 BAIL_IF_NO_MORE_DATA;
    1235           3 :                 DBG_INF_FMT("Def found, length %lu, persistent=%u", len, packet->persistent_alloc);
    1236           3 :                 meta->def = mnd_pemalloc(len + 1, packet->persistent_alloc);
    1237           3 :                 if (!meta->def) {
    1238           0 :                         SET_OOM_ERROR(*conn->error_info);
    1239           0 :                         DBG_RETURN(FAIL);               
    1240             :                 }
    1241           3 :                 memcpy(meta->def, p, len);
    1242           3 :                 meta->def[len] = '\0';
    1243           3 :                 meta->def_length = len;
    1244           3 :                 p += len;
    1245             :         }
    1246             : 
    1247       23796 :         DBG_INF_FMT("allocing root. persistent=%u", packet->persistent_alloc);
    1248       23796 :         root_ptr = meta->root = mnd_pemalloc(total_len, packet->persistent_alloc);
    1249       23796 :         if (!root_ptr) {
    1250           0 :                 SET_OOM_ERROR(*conn->error_info);
    1251           0 :                 DBG_RETURN(FAIL);       
    1252             :         }
    1253             :         
    1254       23796 :         meta->root_len = total_len;
    1255             :         /* Now do allocs */
    1256       23796 :         if (meta->catalog && meta->catalog != mysqlnd_empty_string) {
    1257       23796 :                 len = meta->catalog_length;
    1258       23796 :                 meta->catalog = memcpy(root_ptr, meta->catalog, len);
    1259       23796 :                 *(root_ptr +=len) = '\0';
    1260       23796 :                 root_ptr++;
    1261             :         }
    1262             : 
    1263       23796 :         if (meta->db && meta->db != mysqlnd_empty_string) {
    1264       17663 :                 len = meta->db_length;
    1265       17663 :                 meta->db = memcpy(root_ptr, meta->db, len);
    1266       17663 :                 *(root_ptr +=len) = '\0';
    1267       17663 :                 root_ptr++;
    1268             :         }
    1269             : 
    1270       23796 :         if (meta->table && meta->table != mysqlnd_empty_string) {
    1271       18083 :                 len = meta->table_length;
    1272       18083 :                 meta->table = memcpy(root_ptr, meta->table, len);
    1273       18083 :                 *(root_ptr +=len) = '\0';
    1274       18083 :                 root_ptr++;
    1275             :         }
    1276             : 
    1277       23796 :         if (meta->org_table && meta->org_table != mysqlnd_empty_string) {
    1278       17663 :                 len = meta->org_table_length;
    1279       17663 :                 meta->org_table = memcpy(root_ptr, meta->org_table, len);
    1280       17663 :                 *(root_ptr +=len) = '\0';
    1281       17663 :                 root_ptr++;
    1282             :         }
    1283             : 
    1284       23796 :         if (meta->name && meta->name != mysqlnd_empty_string) {
    1285       23787 :                 len = meta->name_length;
    1286       23787 :                 meta->name = memcpy(root_ptr, meta->name, len);
    1287       23787 :                 *(root_ptr +=len) = '\0';
    1288       23787 :                 root_ptr++;
    1289             :         }
    1290             : 
    1291       23796 :         if (meta->org_name && meta->org_name != mysqlnd_empty_string) {
    1292       18121 :                 len = meta->org_name_length;
    1293       18121 :                 meta->org_name = memcpy(root_ptr, meta->org_name, len);
    1294       18121 :                 *(root_ptr +=len) = '\0';
    1295       18121 :                 root_ptr++;
    1296             :         }
    1297             : 
    1298       23796 :         DBG_INF_FMT("FIELD=[%s.%s.%s]", meta->db? meta->db:"*NA*", meta->table? meta->table:"*NA*",
    1299       23796 :                                 meta->name? meta->name:"*NA*");
    1300             : 
    1301       23796 :         DBG_RETURN(PASS);
    1302             : 
    1303             : faulty_or_fake:
    1304           0 :         DBG_ERR_FMT("Protocol error. Server sent NULL_LENGTH. The server is faulty");
    1305           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Protocol error. Server sent NULL_LENGTH."
    1306             :                                          " The server is faulty");
    1307           0 :         DBG_RETURN(FAIL);
    1308             : premature_end:
    1309           0 :         DBG_ERR_FMT("RSET field packet %d bytes shorter than expected", p - begin - packet->header.size);
    1310           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Result set field packet "MYSQLND_SZ_T_SPEC" bytes "
    1311           0 :                                         "shorter than expected", p - begin - packet->header.size);
    1312           0 :         DBG_RETURN(FAIL);
    1313             : }
    1314             : /* }}} */
    1315             : 
    1316             : 
    1317             : /* {{{ php_mysqlnd_rset_field_free_mem */
    1318             : static
    1319        7888 : void php_mysqlnd_rset_field_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
    1320             : {
    1321        7888 :         MYSQLND_PACKET_RES_FIELD *p= (MYSQLND_PACKET_RES_FIELD *) _packet;
    1322             :         /* p->metadata was passed to us as temporal buffer */
    1323        7888 :         if (!stack_allocation) {
    1324        7888 :                 mnd_pefree(p, p->header.persistent);
    1325             :         }
    1326        7888 : }
    1327             : /* }}} */
    1328             : 
    1329             : 
    1330             : /* {{{ php_mysqlnd_read_row_ex */
    1331             : static enum_func_status
    1332       85556 : php_mysqlnd_read_row_ex(MYSQLND_CONN_DATA * conn, MYSQLND_MEMORY_POOL * result_set_memory_pool,
    1333             :                                                 MYSQLND_MEMORY_POOL_CHUNK ** buffer,
    1334             :                                                 size_t * data_size, zend_bool persistent_alloc,
    1335             :                                                 unsigned int prealloc_more_bytes TSRMLS_DC)
    1336             : {
    1337       85556 :         enum_func_status ret = PASS;
    1338             :         MYSQLND_PACKET_HEADER header;
    1339       85556 :         zend_uchar * p = NULL;
    1340       85556 :         zend_bool first_iteration = TRUE;
    1341             : 
    1342       85556 :         DBG_ENTER("php_mysqlnd_read_row_ex");
    1343             : 
    1344             :         /*
    1345             :           To ease the process the server splits everything in packets up to 2^24 - 1.
    1346             :           Even in the case the payload is evenly divisible by this value, the last
    1347             :           packet will be empty, namely 0 bytes. Thus, we can read every packet and ask
    1348             :           for next one if they have 2^24 - 1 sizes. But just read the header of a
    1349             :           zero-length byte, don't read the body, there is no such.
    1350             :         */
    1351             : 
    1352       85556 :         *data_size = prealloc_more_bytes;
    1353             :         while (1) {
    1354       85556 :                 if (FAIL == mysqlnd_read_header(conn->net, &header, conn->stats, conn->error_info TSRMLS_CC)) {
    1355           2 :                         ret = FAIL;
    1356           2 :                         break;
    1357             :                 }
    1358             : 
    1359       85554 :                 *data_size += header.size;
    1360             : 
    1361       85554 :                 if (first_iteration) {
    1362       85554 :                         first_iteration = FALSE;
    1363             :                         /*
    1364             :                           We need a trailing \0 for the last string, in case of text-mode,
    1365             :                           to be able to implement read-only variables. Thus, we add + 1.
    1366             :                         */
    1367       85554 :                         *buffer = result_set_memory_pool->get_chunk(result_set_memory_pool, *data_size + 1 TSRMLS_CC);
    1368       85554 :                         if (!*buffer) {
    1369           0 :                                 ret = FAIL;
    1370           0 :                                 break;
    1371             :                         }
    1372       85554 :                         p = (*buffer)->ptr;
    1373           0 :                 } else if (!first_iteration) {
    1374             :                         /* Empty packet after MYSQLND_MAX_PACKET_SIZE packet. That's ok, break */
    1375           0 :                         if (!header.size) {
    1376           0 :                                 break;
    1377             :                         }
    1378             : 
    1379             :                         /*
    1380             :                           We have to realloc the buffer.
    1381             : 
    1382             :                           We need a trailing \0 for the last string, in case of text-mode,
    1383             :                           to be able to implement read-only variables.
    1384             :                         */
    1385           0 :                         if (FAIL == (*buffer)->resize_chunk((*buffer), *data_size + 1 TSRMLS_CC)) {
    1386           0 :                                 SET_OOM_ERROR(*conn->error_info);
    1387           0 :                                 ret = FAIL;
    1388           0 :                                 break;
    1389             :                         }
    1390             :                         /* The position could have changed, recalculate */
    1391           0 :                         p = (*buffer)->ptr + (*data_size - header.size);
    1392             :                 }
    1393             : 
    1394       85554 :                 if (PASS != (ret = conn->net->m.receive_ex(conn->net, p, header.size, conn->stats, conn->error_info TSRMLS_CC))) {
    1395           0 :                         DBG_ERR("Empty row packet body");
    1396           0 :                         php_error(E_WARNING, "Empty row packet body");
    1397           0 :                         break;
    1398             :                 }
    1399             : 
    1400       85554 :                 if (header.size < MYSQLND_MAX_PACKET_SIZE) {
    1401       85554 :                         break;
    1402             :                 }
    1403           0 :         }
    1404       85556 :         if (ret == FAIL && *buffer) {
    1405           0 :                 (*buffer)->free_chunk((*buffer) TSRMLS_CC);
    1406           0 :                 *buffer = NULL;
    1407             :         }
    1408       85556 :         *data_size -= prealloc_more_bytes;
    1409       85556 :         DBG_RETURN(ret);
    1410             : }
    1411             : /* }}} */
    1412             : 
    1413             : 
    1414             : /* {{{ php_mysqlnd_rowp_read_binary_protocol */
    1415             : enum_func_status
    1416       20098 : php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
    1417             :                                                                           unsigned int field_count, MYSQLND_FIELD *fields_metadata,
    1418             :                                                                           zend_bool as_unicode, zend_bool as_int_or_float,
    1419             :                                                                           MYSQLND_STATS * stats TSRMLS_DC)
    1420             : {
    1421             :         unsigned int i;
    1422       20098 :         zend_uchar * p = row_buffer->ptr;
    1423             :         zend_uchar * null_ptr, bit;
    1424             :         zval **current_field, **end_field, **start_field;
    1425             : 
    1426       20098 :         DBG_ENTER("php_mysqlnd_rowp_read_binary_protocol");
    1427             : 
    1428       20098 :         if (!fields) {
    1429           0 :                 DBG_RETURN(FAIL);
    1430             :         }
    1431             : 
    1432       20098 :         end_field = (start_field = fields) + field_count;
    1433             : 
    1434             :         /* skip the first byte, not EODATA_MARKER -> 0x0, status */
    1435       20098 :         p++;
    1436       20098 :         null_ptr= p;
    1437       20098 :         p += (field_count + 9)/8;       /* skip null bits */
    1438       20098 :         bit     = 4;                                    /* first 2 bits are reserved */
    1439             : 
    1440       64324 :         for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) {
    1441       44226 :                 DBG_INF("Directly creating zval");
    1442       44226 :                 MAKE_STD_ZVAL(*current_field);
    1443       44226 :                 if (!*current_field) {
    1444           0 :                         DBG_RETURN(FAIL);
    1445             :                 }
    1446             :         }
    1447             : 
    1448       64324 :         for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) {
    1449             :                 enum_mysqlnd_collected_stats statistic;
    1450       44226 :                 zend_uchar * orig_p = p;
    1451             : 
    1452      309582 :                 DBG_INF_FMT("Into zval=%p decoding column %u [%s.%s.%s] type=%u field->flags&unsigned=%u flags=%u is_bit=%u as_unicode=%u",
    1453             :                         *current_field, i,
    1454      132678 :                         fields_metadata[i].db, fields_metadata[i].table, fields_metadata[i].name, fields_metadata[i].type,
    1455      132678 :                         fields_metadata[i].flags & UNSIGNED_FLAG, fields_metadata[i].flags, fields_metadata[i].type == MYSQL_TYPE_BIT, as_unicode);
    1456       44226 :                 if (*null_ptr & bit) {
    1457        1153 :                         DBG_INF("It's null");
    1458        1153 :                         ZVAL_NULL(*current_field);
    1459        1153 :                         statistic = STAT_BINARY_TYPE_FETCHED_NULL;
    1460             :                 } else {
    1461       43073 :                         enum_mysqlnd_field_types type = fields_metadata[i].type;
    1462       43073 :                         mysqlnd_ps_fetch_functions[type].func(*current_field, &fields_metadata[i], 0, &p, as_unicode TSRMLS_CC);
    1463             : 
    1464       43073 :                         if (MYSQLND_G(collect_statistics)) {
    1465       43073 :                                 switch (fields_metadata[i].type) {
    1466           0 :                                         case MYSQL_TYPE_DECIMAL:        statistic = STAT_BINARY_TYPE_FETCHED_DECIMAL; break;
    1467          60 :                                         case MYSQL_TYPE_TINY:           statistic = STAT_BINARY_TYPE_FETCHED_INT8; break;
    1468          43 :                                         case MYSQL_TYPE_SHORT:          statistic = STAT_BINARY_TYPE_FETCHED_INT16; break;
    1469       19070 :                                         case MYSQL_TYPE_LONG:           statistic = STAT_BINARY_TYPE_FETCHED_INT32; break;
    1470         160 :                                         case MYSQL_TYPE_FLOAT:          statistic = STAT_BINARY_TYPE_FETCHED_FLOAT; break;
    1471          61 :                                         case MYSQL_TYPE_DOUBLE:         statistic = STAT_BINARY_TYPE_FETCHED_DOUBLE; break;
    1472           0 :                                         case MYSQL_TYPE_NULL:           statistic = STAT_BINARY_TYPE_FETCHED_NULL; break;
    1473          17 :                                         case MYSQL_TYPE_TIMESTAMP:      statistic = STAT_BINARY_TYPE_FETCHED_TIMESTAMP; break;
    1474        2050 :                                         case MYSQL_TYPE_LONGLONG:       statistic = STAT_BINARY_TYPE_FETCHED_INT64; break;
    1475          28 :                                         case MYSQL_TYPE_INT24:          statistic = STAT_BINARY_TYPE_FETCHED_INT24; break;
    1476          19 :                                         case MYSQL_TYPE_DATE:           statistic = STAT_BINARY_TYPE_FETCHED_DATE; break;
    1477          19 :                                         case MYSQL_TYPE_TIME:           statistic = STAT_BINARY_TYPE_FETCHED_TIME; break;
    1478          19 :                                         case MYSQL_TYPE_DATETIME:       statistic = STAT_BINARY_TYPE_FETCHED_DATETIME; break;
    1479          19 :                                         case MYSQL_TYPE_YEAR:           statistic = STAT_BINARY_TYPE_FETCHED_YEAR; break;
    1480           1 :                                         case MYSQL_TYPE_NEWDATE:        statistic = STAT_BINARY_TYPE_FETCHED_DATE; break;
    1481           0 :                                         case MYSQL_TYPE_VARCHAR:        statistic = STAT_BINARY_TYPE_FETCHED_STRING; break;
    1482        1487 :                                         case MYSQL_TYPE_BIT:            statistic = STAT_BINARY_TYPE_FETCHED_BIT; break;
    1483          61 :                                         case MYSQL_TYPE_NEWDECIMAL:     statistic = STAT_BINARY_TYPE_FETCHED_DECIMAL; break;
    1484           0 :                                         case MYSQL_TYPE_ENUM:           statistic = STAT_BINARY_TYPE_FETCHED_ENUM; break;
    1485           0 :                                         case MYSQL_TYPE_SET:            statistic = STAT_BINARY_TYPE_FETCHED_SET; break;
    1486           0 :                                         case MYSQL_TYPE_TINY_BLOB:      statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break;
    1487           9 :                                         case MYSQL_TYPE_MEDIUM_BLOB:statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break;
    1488           0 :                                         case MYSQL_TYPE_LONG_BLOB:      statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break;
    1489        1164 :                                         case MYSQL_TYPE_BLOB:           statistic = STAT_BINARY_TYPE_FETCHED_BLOB; break;
    1490       18458 :                                         case MYSQL_TYPE_VAR_STRING:     statistic = STAT_BINARY_TYPE_FETCHED_STRING; break;
    1491         280 :                                         case MYSQL_TYPE_STRING:         statistic = STAT_BINARY_TYPE_FETCHED_STRING; break;
    1492          48 :                                         case MYSQL_TYPE_GEOMETRY:       statistic = STAT_BINARY_TYPE_FETCHED_GEOMETRY; break;
    1493           0 :                                         default: statistic = STAT_BINARY_TYPE_FETCHED_OTHER; break;
    1494             :                                 }
    1495             :                         }
    1496             :                 }
    1497       44226 :                 MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, statistic, 1,
    1498             :                                                                                 STAT_BYTES_RECEIVED_PURE_DATA_PS,
    1499             :                                                                                 (Z_TYPE_PP(current_field) == IS_STRING)?
    1500             :                                                                                         Z_STRLEN_PP(current_field) : (p - orig_p));
    1501             : 
    1502       44226 :                 if (!((bit<<=1) & 255)) {
    1503         162 :                         bit = 1;        /* to the following byte */
    1504         162 :                         null_ptr++;
    1505             :                 }
    1506             :         }
    1507             : 
    1508       20098 :         DBG_RETURN(PASS);
    1509             : }
    1510             : /* }}} */
    1511             : 
    1512             : 
    1513             : /* {{{ php_mysqlnd_rowp_read_text_protocol */
    1514             : enum_func_status
    1515       59158 : php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
    1516             :                                                                         unsigned int field_count, MYSQLND_FIELD *fields_metadata,
    1517             :                                                                         zend_bool as_unicode, zend_bool as_int_or_float,
    1518             :                                                                         MYSQLND_STATS * stats TSRMLS_DC)
    1519             : {
    1520             :         unsigned int i;
    1521       59158 :         zend_bool last_field_was_string = FALSE;
    1522             :         zval **current_field, **end_field, **start_field;
    1523       59158 :         zend_uchar * p = row_buffer->ptr;
    1524       59158 :         size_t data_size = row_buffer->app;
    1525       59158 :         zend_uchar * bit_area = (zend_uchar*) row_buffer->ptr + data_size + 1; /* we allocate from here */
    1526             : 
    1527       59158 :         DBG_ENTER("php_mysqlnd_rowp_read_text_protocol");
    1528             : 
    1529       59158 :         if (!fields) {
    1530           0 :                 DBG_RETURN(FAIL);
    1531             :         }
    1532             : 
    1533       59158 :         end_field = (start_field = fields) + field_count;
    1534             : 
    1535      179638 :         for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) {
    1536      120480 :                 DBG_INF("Directly creating zval");
    1537      120480 :                 MAKE_STD_ZVAL(*current_field);
    1538      120480 :                 if (!*current_field) {
    1539           0 :                         DBG_RETURN(FAIL);
    1540             :                 }
    1541             :         }
    1542             : 
    1543      179638 :         for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) {
    1544             :                 /* Don't reverse the order. It is significant!*/
    1545      120480 :                 zend_uchar *this_field_len_pos = p;
    1546             :                 /* php_mysqlnd_net_field_length() call should be after *this_field_len_pos = p; */
    1547      120480 :                 unsigned long len = php_mysqlnd_net_field_length(&p);
    1548             : 
    1549      120480 :                 if (current_field > start_field && last_field_was_string) {
    1550             :                         /*
    1551             :                           Normal queries:
    1552             :                           We have to put \0 now to the end of the previous field, if it was
    1553             :                           a string. IS_NULL doesn't matter. Because we have already read our
    1554             :                           length, then we can overwrite it in the row buffer.
    1555             :                           This statement terminates the previous field, not the current one.
    1556             : 
    1557             :                           NULL_LENGTH is encoded in one byte, so we can stick a \0 there.
    1558             :                           Any string's length is encoded in at least one byte, so we can stick
    1559             :                           a \0 there.
    1560             :                         */
    1561             : 
    1562       61270 :                         *this_field_len_pos = '\0';
    1563             :                 }
    1564             : 
    1565             :                 /* NULL or NOT NULL, this is the question! */
    1566      120480 :                 if (len == MYSQLND_NULL_LENGTH) {
    1567         734 :                         ZVAL_NULL(*current_field);
    1568         734 :                         last_field_was_string = FALSE;
    1569             :                 } else {
    1570             : #if MYSQLND_UNICODE || defined(MYSQLND_STRING_TO_INT_CONVERSION)
    1571             :                         struct st_mysqlnd_perm_bind perm_bind =
    1572      119746 :                                         mysqlnd_ps_fetch_functions[fields_metadata[i].type];
    1573             : #endif
    1574      119746 :                         if (MYSQLND_G(collect_statistics)) {
    1575             :                                 enum_mysqlnd_collected_stats statistic;
    1576      119746 :                                 switch (fields_metadata[i].type) {
    1577           0 :                                         case MYSQL_TYPE_DECIMAL:        statistic = STAT_TEXT_TYPE_FETCHED_DECIMAL; break;
    1578          41 :                                         case MYSQL_TYPE_TINY:           statistic = STAT_TEXT_TYPE_FETCHED_INT8; break;
    1579          40 :                                         case MYSQL_TYPE_SHORT:          statistic = STAT_TEXT_TYPE_FETCHED_INT16; break;
    1580       58309 :                                         case MYSQL_TYPE_LONG:           statistic = STAT_TEXT_TYPE_FETCHED_INT32; break;
    1581          35 :                                         case MYSQL_TYPE_FLOAT:          statistic = STAT_TEXT_TYPE_FETCHED_FLOAT; break;
    1582          35 :                                         case MYSQL_TYPE_DOUBLE:         statistic = STAT_TEXT_TYPE_FETCHED_DOUBLE; break;
    1583           0 :                                         case MYSQL_TYPE_NULL:           statistic = STAT_TEXT_TYPE_FETCHED_NULL; break;
    1584          35 :                                         case MYSQL_TYPE_TIMESTAMP:      statistic = STAT_TEXT_TYPE_FETCHED_TIMESTAMP; break;
    1585        1346 :                                         case MYSQL_TYPE_LONGLONG:       statistic = STAT_TEXT_TYPE_FETCHED_INT64; break;
    1586          27 :                                         case MYSQL_TYPE_INT24:          statistic = STAT_TEXT_TYPE_FETCHED_INT24; break;
    1587          16 :                                         case MYSQL_TYPE_DATE:           statistic = STAT_TEXT_TYPE_FETCHED_DATE; break;
    1588          16 :                                         case MYSQL_TYPE_TIME:           statistic = STAT_TEXT_TYPE_FETCHED_TIME; break;
    1589          18 :                                         case MYSQL_TYPE_DATETIME:       statistic = STAT_TEXT_TYPE_FETCHED_DATETIME; break;
    1590          16 :                                         case MYSQL_TYPE_YEAR:           statistic = STAT_TEXT_TYPE_FETCHED_YEAR; break;
    1591           1 :                                         case MYSQL_TYPE_NEWDATE:        statistic = STAT_TEXT_TYPE_FETCHED_DATE; break;
    1592           0 :                                         case MYSQL_TYPE_VARCHAR:        statistic = STAT_TEXT_TYPE_FETCHED_STRING; break;
    1593         464 :                                         case MYSQL_TYPE_BIT:            statistic = STAT_TEXT_TYPE_FETCHED_BIT; break;
    1594          35 :                                         case MYSQL_TYPE_NEWDECIMAL:     statistic = STAT_TEXT_TYPE_FETCHED_DECIMAL; break;
    1595           0 :                                         case MYSQL_TYPE_ENUM:           statistic = STAT_TEXT_TYPE_FETCHED_ENUM; break;
    1596           0 :                                         case MYSQL_TYPE_SET:            statistic = STAT_TEXT_TYPE_FETCHED_SET; break;
    1597           0 :                                         case MYSQL_TYPE_TINY_BLOB:      statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
    1598          20 :                                         case MYSQL_TYPE_MEDIUM_BLOB:statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
    1599           0 :                                         case MYSQL_TYPE_LONG_BLOB:      statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
    1600         174 :                                         case MYSQL_TYPE_BLOB:           statistic = STAT_TEXT_TYPE_FETCHED_BLOB; break;
    1601       18424 :                                         case MYSQL_TYPE_VAR_STRING:     statistic = STAT_TEXT_TYPE_FETCHED_STRING; break;
    1602       40646 :                                         case MYSQL_TYPE_STRING:         statistic = STAT_TEXT_TYPE_FETCHED_STRING; break;
    1603          48 :                                         case MYSQL_TYPE_GEOMETRY:       statistic = STAT_TEXT_TYPE_FETCHED_GEOMETRY; break;
    1604           0 :                                         default: statistic = STAT_TEXT_TYPE_FETCHED_OTHER; break;
    1605             :                                 }
    1606      119746 :                                 MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, statistic, 1, STAT_BYTES_RECEIVED_PURE_DATA_TEXT, len);
    1607             :                         }
    1608             : #ifdef MYSQLND_STRING_TO_INT_CONVERSION
    1609      119754 :                         if (as_int_or_float && perm_bind.php_type == IS_LONG) {
    1610           8 :                                 zend_uchar save = *(p + len);
    1611             :                                 /* We have to make it ASCIIZ temporarily */
    1612           8 :                                 *(p + len) = '\0';
    1613           8 :                                 if (perm_bind.pack_len < SIZEOF_LONG) {
    1614             :                                         /* direct conversion */
    1615             :                                         int64_t v =
    1616             : #ifndef PHP_WIN32
    1617           6 :                                                 atoll((char *) p);
    1618             : #else
    1619             :                                                 _atoi64((char *) p);
    1620             : #endif
    1621           6 :                                         ZVAL_LONG(*current_field, (long) v); /* the cast is safe */
    1622             :                                 } else {
    1623             :                                         uint64_t v =
    1624             : #ifndef PHP_WIN32
    1625           2 :                                                 (uint64_t) atoll((char *) p);
    1626             : #else
    1627             :                                                 (uint64_t) _atoi64((char *) p);
    1628             : #endif
    1629           2 :                                         zend_bool uns = fields_metadata[i].flags & UNSIGNED_FLAG? TRUE:FALSE;
    1630             :                                         /* We have to make it ASCIIZ temporarily */
    1631             : #if SIZEOF_LONG==8
    1632           2 :                                         if (uns == TRUE && v > 9223372036854775807L)
    1633             : #elif SIZEOF_LONG==4
    1634             :                                         if ((uns == TRUE && v > L64(2147483647)) ||
    1635             :                                                 (uns == FALSE && (( L64(2147483647) < (int64_t) v) ||
    1636             :                                                 (L64(-2147483648) > (int64_t) v))))
    1637             : #else
    1638             : #error Need fix for this architecture
    1639             : #endif /* SIZEOF */
    1640             :                                         {
    1641           0 :                                                 ZVAL_STRINGL(*current_field, (char *)p, len, 0);
    1642             :                                         } else {
    1643           2 :                                                 ZVAL_LONG(*current_field, (long) v); /* the cast is safe */
    1644             :                                         }
    1645             :                                 }
    1646           8 :                                 *(p + len) = save;
    1647      119740 :                         } else if (as_int_or_float && perm_bind.php_type == IS_DOUBLE) {
    1648           2 :                                 zend_uchar save = *(p + len);
    1649             :                                 /* We have to make it ASCIIZ temporarily */
    1650           2 :                                 *(p + len) = '\0';
    1651           2 :                                 ZVAL_DOUBLE(*current_field, atof((char *) p));
    1652           2 :                                 *(p + len) = save;
    1653             :                         } else
    1654             : #endif /* MYSQLND_STRING_TO_INT_CONVERSION */
    1655      119736 :                         if (fields_metadata[i].type == MYSQL_TYPE_BIT) {
    1656             :                                 /*
    1657             :                                   BIT fields are specially handled. As they come as bit mask, we have
    1658             :                                   to convert it to human-readable representation. As the bits take
    1659             :                                   less space in the protocol than the numbers they represent, we don't
    1660             :                                   have enough space in the packet buffer to overwrite inside.
    1661             :                                   Thus, a bit more space is pre-allocated at the end of the buffer,
    1662             :                                   see php_mysqlnd_rowp_read(). And we add the strings at the end.
    1663             :                                   Definitely not nice, _hackish_ :(, but works.
    1664             :                                 */
    1665         463 :                                 zend_uchar *start = bit_area;
    1666         463 :                                 ps_fetch_from_1_to_8_bytes(*current_field, &(fields_metadata[i]), 0, &p, as_unicode, len TSRMLS_CC);
    1667             :                                 /*
    1668             :                                   We have advanced in ps_fetch_from_1_to_8_bytes. We should go back because
    1669             :                                   later in this function there will be an advancement.
    1670             :                                 */
    1671         463 :                                 p -= len;
    1672         463 :                                 if (Z_TYPE_PP(current_field) == IS_LONG) {
    1673         463 :                                         bit_area += 1 + sprintf((char *)start, "%ld", Z_LVAL_PP(current_field));
    1674             : #if MYSQLND_UNICODE
    1675             :                                         if (as_unicode) {
    1676             :                                                 ZVAL_UTF8_STRINGL(*current_field, start, bit_area - start - 1, 0);
    1677             :                                         } else
    1678             : #endif
    1679             :                                         {
    1680         463 :                                                 ZVAL_STRINGL(*current_field, (char *) start, bit_area - start - 1, 0);
    1681             :                                         }
    1682           0 :                                 } else if (Z_TYPE_PP(current_field) == IS_STRING){
    1683           0 :                                         memcpy(bit_area, Z_STRVAL_PP(current_field), Z_STRLEN_PP(current_field));
    1684           0 :                                         bit_area += Z_STRLEN_PP(current_field);
    1685           0 :                                         *bit_area++ = '\0';
    1686           0 :                                         zval_dtor(*current_field);
    1687             : #if MYSQLND_UNICODE
    1688             :                                         if (as_unicode) {
    1689             :                                                 ZVAL_UTF8_STRINGL(*current_field, start, bit_area - start - 1, 0);
    1690             :                                         } else
    1691             : #endif
    1692             :                                         {
    1693           0 :                                                 ZVAL_STRINGL(*current_field, (char *) start, bit_area - start - 1, 0);
    1694             :                                         }
    1695             :                                 }
    1696             :                                 /*
    1697             :                                   IS_UNICODE should not be specially handled. In unicode mode
    1698             :                                   the buffers are not referenced - everything is copied.
    1699             :                                 */
    1700             :                         } else
    1701             : #if MYSQLND_UNICODE == 0
    1702             :                         {
    1703      119273 :                                 ZVAL_STRINGL(*current_field, (char *)p, len, 0);
    1704             :                         }
    1705             : #else
    1706             :                         /*
    1707             :                           Here we have to convert to UTF16, which means not reusing the buffer.
    1708             :                           Which in turn means that we can free the buffers once we have
    1709             :                           stored the result set, if we use store_result().
    1710             : 
    1711             :                           Also the destruction of the zvals should not call zval_copy_ctor()
    1712             :                           because then we will leak.
    1713             : 
    1714             :                           XXX: Keep in mind that up there there is an open `else` in
    1715             :                           #ifdef MYSQLND_STRING_TO_INT_CONVERSION
    1716             :                           which will make with this `if` an `else if`.
    1717             :                         */
    1718             :                         if ((perm_bind.is_possibly_blob == TRUE &&
    1719             :                                  fields_metadata[i].charsetnr == MYSQLND_BINARY_CHARSET_NR) ||
    1720             :                                 (!as_unicode && perm_bind.can_ret_as_str_in_uni == TRUE))
    1721             :                         {
    1722             :                                 /* BLOB - no conversion please */
    1723             :                                 ZVAL_STRINGL(*current_field, (char *)p, len, 0);
    1724             :                         } else {
    1725             :                                 ZVAL_UTF8_STRINGL(*current_field, (char *)p, len, 0);
    1726             :                         }
    1727             : #endif
    1728      119746 :                         p += len;
    1729      119746 :                         last_field_was_string = TRUE;
    1730             :                 }
    1731             :         }
    1732       59158 :         if (last_field_was_string) {
    1733             :                 /* Normal queries: The buffer has one more byte at the end, because we need it */
    1734       58476 :                 row_buffer->ptr[data_size] = '\0';
    1735             :         }
    1736             : 
    1737       59158 :         DBG_RETURN(PASS);
    1738             : }
    1739             : /* }}} */
    1740             : 
    1741             : 
    1742             : /* {{{ php_mysqlnd_rowp_read */
    1743             : /*
    1744             :   if normal statements => packet->fields is created by this function,
    1745             :   if PS => packet->fields is passed from outside
    1746             : */
    1747             : static enum_func_status
    1748       85556 : php_mysqlnd_rowp_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
    1749             : {
    1750       85556 :         MYSQLND_NET * net = conn->net;
    1751             :         zend_uchar *p;
    1752       85556 :         enum_func_status ret = PASS;
    1753       85556 :         size_t old_chunk_size = net->stream->chunk_size;
    1754       85556 :         MYSQLND_PACKET_ROW *packet= (MYSQLND_PACKET_ROW *) _packet;
    1755       85556 :         size_t post_alloc_for_bit_fields = 0;
    1756       85556 :         size_t data_size = 0;
    1757             : 
    1758       85556 :         DBG_ENTER("php_mysqlnd_rowp_read");
    1759             : 
    1760       85556 :         if (!packet->binary_protocol && packet->bit_fields_count) {
    1761             :                 /* For every field we need terminating \0 */
    1762         970 :                 post_alloc_for_bit_fields = packet->bit_fields_total_len + packet->bit_fields_count;
    1763             :         }
    1764             : 
    1765      171112 :         ret = php_mysqlnd_read_row_ex(conn, packet->result_set_memory_pool, &packet->row_buffer, &data_size,
    1766       85556 :                                                                   packet->persistent_alloc, post_alloc_for_bit_fields
    1767             :                                                                   TSRMLS_CC);
    1768       85556 :         if (FAIL == ret) {
    1769           2 :                 goto end;
    1770             :         }
    1771       85554 :         MYSQLND_INC_CONN_STATISTIC_W_VALUE2(conn->stats, packet_type_to_statistic_byte_count[PROT_ROW_PACKET],
    1772             :                                                                                 MYSQLND_HEADER_SIZE + packet->header.size,
    1773             :                                                                                 packet_type_to_statistic_packet_count[PROT_ROW_PACKET],
    1774             :                                                                                 1);
    1775             : 
    1776             :         /* packet->row_buffer->ptr is of size 'data_size + 1' */
    1777       85554 :         packet->header.size = data_size;
    1778       85554 :         packet->row_buffer->app = data_size;
    1779             : 
    1780       85554 :         if (ERROR_MARKER == (*(p = packet->row_buffer->ptr))) {
    1781             :                 /*
    1782             :                    Error message as part of the result set,
    1783             :                    not good but we should not hang. See:
    1784             :                    Bug #27876 : SF with cyrillic variable name fails during execution
    1785             :                 */
    1786           0 :                 ret = FAIL;
    1787           0 :                 php_mysqlnd_read_error_from_line(p + 1, data_size - 1,
    1788             :                                                                                  packet->error_info.error,
    1789             :                                                                                  sizeof(packet->error_info.error),
    1790             :                                                                                  &packet->error_info.error_no,
    1791             :                                                                                  packet->error_info.sqlstate
    1792             :                                                                                  TSRMLS_CC);
    1793       90193 :         } else if (EODATA_MARKER == *p && data_size < 8) { /* EOF */
    1794        4639 :                 packet->eof = TRUE;
    1795        4639 :                 p++;
    1796        4639 :                 if (data_size > 1) {
    1797        4639 :                         packet->warning_count = uint2korr(p);
    1798        4639 :                         p += 2;
    1799        4639 :                         packet->server_status = uint2korr(p);
    1800             :                         /* Seems we have 3 bytes reserved for future use */
    1801        4639 :                         DBG_INF_FMT("server_status=%u warning_count=%u", packet->server_status, packet->warning_count);
    1802             :                 }
    1803             :         } else {
    1804       80915 :                 MYSQLND_INC_CONN_STATISTIC(conn->stats,
    1805             :                                                                         packet->binary_protocol? STAT_ROWS_FETCHED_FROM_SERVER_PS:
    1806             :                                                                                                                          STAT_ROWS_FETCHED_FROM_SERVER_NORMAL);
    1807             : 
    1808       80915 :                 packet->eof = FALSE;
    1809             :                 /* packet->field_count is set by the user of the packet */
    1810             : 
    1811       80915 :                 if (!packet->skip_extraction) {
    1812       17693 :                         if (!packet->fields) {
    1813       17693 :                                 DBG_INF("Allocating packet->fields");
    1814             :                                 /*
    1815             :                                   old-API will probably set packet->fields to NULL every time, though for
    1816             :                                   unbuffered sets it makes not much sense as the zvals in this buffer matter,
    1817             :                                   not the buffer. Constantly allocating and deallocating brings nothing.
    1818             : 
    1819             :                                   For PS - if stmt_store() is performed, thus we don't have a cursor, it will
    1820             :                                   behave just like old-API buffered. Cursors will behave like a bit different,
    1821             :                                   but mostly like old-API unbuffered and thus will populate this array with
    1822             :                                   value.
    1823             :                                 */
    1824       17693 :                                 packet->fields = (zval **) mnd_pecalloc(packet->field_count, sizeof(zval *),
    1825             :                                                                                                                 packet->persistent_alloc);
    1826             :                         }
    1827             :                 } else {
    1828       63222 :                         MYSQLND_INC_CONN_STATISTIC(conn->stats,
    1829             :                                                                                 packet->binary_protocol? STAT_ROWS_SKIPPED_PS:
    1830             :                                                                                                                                  STAT_ROWS_SKIPPED_NORMAL);
    1831             :                 }
    1832             :         }
    1833             : 
    1834             : end:
    1835       85556 :         net->stream->chunk_size = old_chunk_size;
    1836       85556 :         DBG_RETURN(ret);
    1837             : }
    1838             : /* }}} */
    1839             : 
    1840             : 
    1841             : /* {{{ php_mysqlnd_rowp_free_mem */
    1842             : static void
    1843        4624 : php_mysqlnd_rowp_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
    1844             : {
    1845             :         MYSQLND_PACKET_ROW *p;
    1846             : 
    1847        4624 :         DBG_ENTER("php_mysqlnd_rowp_free_mem");
    1848        4624 :         p = (MYSQLND_PACKET_ROW *) _packet;
    1849        4624 :         if (p->row_buffer) {
    1850        4615 :                 p->row_buffer->free_chunk(p->row_buffer TSRMLS_CC);
    1851        4615 :                 p->row_buffer = NULL;
    1852             :         }
    1853        4624 :         DBG_INF_FMT("stack_allocation=%u persistent=%u", (int)stack_allocation, (int)p->header.persistent);
    1854             :         /*
    1855             :           Don't free packet->fields :
    1856             :           - normal queries -> store_result() | fetch_row_unbuffered() will transfer
    1857             :             the ownership and NULL it.
    1858             :           - PS will pass in it the bound variables, we have to use them! and of course
    1859             :             not free the array. As it is passed to us, we should not clean it ourselves.
    1860             :         */
    1861        4624 :         if (!stack_allocation) {
    1862        4624 :                 mnd_pefree(p, p->header.persistent);
    1863             :         }
    1864        4624 :         DBG_VOID_RETURN;
    1865             : }
    1866             : /* }}} */
    1867             : 
    1868             : 
    1869             : /* {{{ php_mysqlnd_stats_read */
    1870             : static enum_func_status
    1871          16 : php_mysqlnd_stats_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
    1872             : {
    1873          16 :         MYSQLND_PACKET_STATS *packet= (MYSQLND_PACKET_STATS *) _packet;
    1874          16 :         size_t buf_len = conn->net->cmd_buffer.length;
    1875          16 :         zend_uchar *buf = (zend_uchar *) conn->net->cmd_buffer.buffer;
    1876             : 
    1877          16 :         DBG_ENTER("php_mysqlnd_stats_read");
    1878             : 
    1879          16 :         PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "statistics", PROT_STATS_PACKET);
    1880             : 
    1881          16 :         packet->message = mnd_emalloc(packet->header.size + 1);
    1882          16 :         memcpy(packet->message, buf, packet->header.size);
    1883          16 :         packet->message[packet->header.size] = '\0';
    1884          16 :         packet->message_len = packet->header.size;
    1885             : 
    1886          16 :         DBG_RETURN(PASS);
    1887             : }
    1888             : /* }}} */
    1889             : 
    1890             : 
    1891             : /* {{{ php_mysqlnd_stats_free_mem */
    1892             : static
    1893          16 : void php_mysqlnd_stats_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
    1894             : {
    1895          16 :         MYSQLND_PACKET_STATS *p= (MYSQLND_PACKET_STATS *) _packet;
    1896          16 :         if (p->message) {
    1897          16 :                 mnd_efree(p->message);
    1898          16 :                 p->message = NULL;
    1899             :         }
    1900          16 :         if (!stack_allocation) {
    1901          16 :                 mnd_pefree(p, p->header.persistent);
    1902             :         }
    1903          16 : }
    1904             : /* }}} */
    1905             : 
    1906             : 
    1907             : /* 1 + 4 (id) + 2 (field_c) + 2 (param_c) + 1 (filler) + 2 (warnings ) */
    1908             : #define PREPARE_RESPONSE_SIZE_41 9
    1909             : #define PREPARE_RESPONSE_SIZE_50 12
    1910             : 
    1911             : /* {{{ php_mysqlnd_prepare_read */
    1912             : static enum_func_status
    1913        4240 : php_mysqlnd_prepare_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
    1914             : {
    1915             :         /* In case of an error, we should have place to put it */
    1916        4240 :         size_t buf_len = conn->net->cmd_buffer.length;
    1917        4240 :         zend_uchar *buf = (zend_uchar *) conn->net->cmd_buffer.buffer;
    1918        4240 :         zend_uchar *p = buf;
    1919        4240 :         zend_uchar *begin = buf;
    1920             :         unsigned int data_size;
    1921        4240 :         MYSQLND_PACKET_PREPARE_RESPONSE *packet= (MYSQLND_PACKET_PREPARE_RESPONSE *) _packet;
    1922             : 
    1923        4240 :         DBG_ENTER("php_mysqlnd_prepare_read");
    1924             : 
    1925        4240 :         PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "prepare", PROT_PREPARE_RESP_PACKET);
    1926        4239 :         BAIL_IF_NO_MORE_DATA;
    1927             : 
    1928        4239 :         data_size = packet->header.size;
    1929        4239 :         packet->error_code = uint1korr(p);
    1930        4239 :         p++;
    1931        4239 :         BAIL_IF_NO_MORE_DATA;
    1932             : 
    1933        4239 :         if (ERROR_MARKER == packet->error_code) {
    1934          26 :                 php_mysqlnd_read_error_from_line(p, data_size - 1,
    1935             :                                                                                  packet->error_info.error,
    1936             :                                                                                  sizeof(packet->error_info.error),
    1937             :                                                                                  &packet->error_info.error_no,
    1938             :                                                                                  packet->error_info.sqlstate
    1939             :                                                                                  TSRMLS_CC);
    1940          26 :                 DBG_RETURN(PASS);
    1941             :         }
    1942             : 
    1943        4213 :         if (data_size != PREPARE_RESPONSE_SIZE_41 &&
    1944             :                 data_size != PREPARE_RESPONSE_SIZE_50 &&
    1945             :                 !(data_size > PREPARE_RESPONSE_SIZE_50)) {
    1946           0 :                 DBG_ERR_FMT("Wrong COM_STMT_PREPARE response size. Received %u", data_size);
    1947           0 :                 php_error(E_WARNING, "Wrong COM_STMT_PREPARE response size. Received %u", data_size);
    1948           0 :                 DBG_RETURN(FAIL);
    1949             :         }
    1950             : 
    1951        4213 :         packet->stmt_id = uint4korr(p);
    1952        4213 :         p += 4;
    1953        4213 :         BAIL_IF_NO_MORE_DATA;
    1954             : 
    1955             :         /* Number of columns in result set */
    1956        4213 :         packet->field_count = uint2korr(p);
    1957        4213 :         p += 2;
    1958        4213 :         BAIL_IF_NO_MORE_DATA;
    1959             : 
    1960        4213 :         packet->param_count = uint2korr(p);
    1961        4213 :         p += 2;
    1962        4213 :         BAIL_IF_NO_MORE_DATA;
    1963             : 
    1964        4213 :         if (data_size > 9) {
    1965             :                 /* 0x0 filler sent by the server for 5.0+ clients */
    1966        4213 :                 p++;
    1967        4213 :                 BAIL_IF_NO_MORE_DATA;
    1968             : 
    1969        4213 :                 packet->warning_count = uint2korr(p);
    1970             :         }
    1971             : 
    1972        4213 :         DBG_INF_FMT("Prepare packet read: stmt_id=%u fields=%u params=%u",
    1973             :                                 packet->stmt_id, packet->field_count, packet->param_count);
    1974             : 
    1975        4213 :         BAIL_IF_NO_MORE_DATA;
    1976             : 
    1977        4213 :         DBG_RETURN(PASS);
    1978             : premature_end:
    1979           0 :         DBG_ERR_FMT("PREPARE packet %d bytes shorter than expected", p - begin - packet->header.size);
    1980           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "PREPARE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
    1981           0 :                                          p - begin - packet->header.size);
    1982           0 :         DBG_RETURN(FAIL);
    1983             : }
    1984             : /* }}} */
    1985             : 
    1986             : 
    1987             : /* {{{ php_mysqlnd_prepare_free_mem */
    1988             : static void
    1989        4240 : php_mysqlnd_prepare_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
    1990             : {
    1991        4240 :         MYSQLND_PACKET_PREPARE_RESPONSE *p= (MYSQLND_PACKET_PREPARE_RESPONSE *) _packet;
    1992        4240 :         if (!stack_allocation) {
    1993        4240 :                 mnd_pefree(p, p->header.persistent);
    1994             :         }
    1995        4240 : }
    1996             : /* }}} */
    1997             : 
    1998             : 
    1999             : /* {{{ php_mysqlnd_chg_user_read */
    2000             : static enum_func_status
    2001          66 : php_mysqlnd_chg_user_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
    2002             : {
    2003             :         /* There could be an error message */
    2004          66 :         size_t buf_len = conn->net->cmd_buffer.length;
    2005          66 :         zend_uchar *buf = (zend_uchar *) conn->net->cmd_buffer.buffer;
    2006          66 :         zend_uchar *p = buf;
    2007          66 :         zend_uchar *begin = buf;
    2008          66 :         MYSQLND_PACKET_CHG_USER_RESPONSE *packet= (MYSQLND_PACKET_CHG_USER_RESPONSE *) _packet;
    2009             : 
    2010          66 :         DBG_ENTER("php_mysqlnd_chg_user_read");
    2011             : 
    2012          66 :         PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "change user response", PROT_CHG_USER_RESP_PACKET);
    2013          66 :         BAIL_IF_NO_MORE_DATA;
    2014             : 
    2015             :         /*
    2016             :           Don't increment. First byte is ERROR_MARKER on error, but otherwise is starting byte
    2017             :           of encoded sequence for length.
    2018             :         */
    2019             : 
    2020             :         /* Should be always 0x0 or ERROR_MARKER for error */
    2021          66 :         packet->response_code = uint1korr(p);
    2022          66 :         p++;
    2023             : 
    2024          66 :         if (packet->header.size == 1 && buf[0] == EODATA_MARKER && packet->server_capabilities & CLIENT_SECURE_CONNECTION) {
    2025             :                 /* We don't handle 3.23 authentication */
    2026           0 :                 packet->server_asked_323_auth = TRUE;
    2027           0 :                 DBG_RETURN(FAIL);
    2028             :         }
    2029             : 
    2030          66 :         if (ERROR_MARKER == packet->response_code) {
    2031          12 :                 php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
    2032             :                                                                                  packet->error_info.error,
    2033             :                                                                                  sizeof(packet->error_info.error),
    2034             :                                                                                  &packet->error_info.error_no,
    2035             :                                                                                  packet->error_info.sqlstate
    2036             :                                                                                  TSRMLS_CC);
    2037             :         }
    2038          66 :         BAIL_IF_NO_MORE_DATA;
    2039          66 :         if (packet->response_code == 0xFE && packet->header.size > (size_t) (p - buf)) {
    2040           0 :                 packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE);
    2041           0 :                 packet->new_auth_protocol_len = strlen(packet->new_auth_protocol);
    2042           0 :                 p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */
    2043           0 :                 packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf);
    2044           0 :                 if (packet->new_auth_protocol_data_len) {
    2045           0 :                         packet->new_auth_protocol_data = mnd_emalloc(packet->new_auth_protocol_data_len);
    2046           0 :                         memcpy(packet->new_auth_protocol_data, p, packet->new_auth_protocol_data_len);
    2047             :                 }
    2048           0 :                 DBG_INF_FMT("The server requested switching auth plugin to : %s", packet->new_auth_protocol);
    2049           0 :                 DBG_INF_FMT("Server salt : [%*s]", packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
    2050             :         }
    2051             : 
    2052          66 :         DBG_RETURN(PASS);
    2053             : premature_end:
    2054           0 :         DBG_ERR_FMT("CHANGE_USER packet %d bytes shorter than expected", p - begin - packet->header.size);
    2055           0 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "CHANGE_USER packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
    2056           0 :                                                  p - begin - packet->header.size);
    2057           0 :         DBG_RETURN(FAIL);
    2058             : }
    2059             : /* }}} */
    2060             : 
    2061             : 
    2062             : /* {{{ php_mysqlnd_chg_user_free_mem */
    2063             : static void
    2064          67 : php_mysqlnd_chg_user_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
    2065             : {
    2066          67 :         MYSQLND_PACKET_CHG_USER_RESPONSE * p = (MYSQLND_PACKET_CHG_USER_RESPONSE *) _packet;
    2067             : 
    2068          67 :         if (p->new_auth_protocol) {
    2069           0 :                 mnd_efree(p->new_auth_protocol);
    2070           0 :                 p->new_auth_protocol = NULL;
    2071             :         }
    2072          67 :         p->new_auth_protocol_len = 0;
    2073             : 
    2074          67 :         if (p->new_auth_protocol_data) {
    2075           0 :                 mnd_efree(p->new_auth_protocol_data);
    2076           0 :                 p->new_auth_protocol_data = NULL;
    2077             :         }
    2078          67 :         p->new_auth_protocol_data_len = 0;
    2079             : 
    2080          67 :         if (!stack_allocation) {
    2081          67 :                 mnd_pefree(p, p->header.persistent);
    2082             :         }
    2083          67 : }
    2084             : /* }}} */
    2085             : 
    2086             : 
    2087             : /* {{{ packet_methods */
    2088             : static
    2089             : mysqlnd_packet_methods packet_methods[PROT_LAST] =
    2090             : {
    2091             :         {
    2092             :                 sizeof(MYSQLND_PACKET_GREET),
    2093             :                 php_mysqlnd_greet_read,
    2094             :                 NULL, /* write */
    2095             :                 php_mysqlnd_greet_free_mem,
    2096             :         }, /* PROT_GREET_PACKET */
    2097             :         {
    2098             :                 sizeof(MYSQLND_PACKET_AUTH),
    2099             :                 NULL, /* read */
    2100             :                 php_mysqlnd_auth_write,
    2101             :                 php_mysqlnd_auth_free_mem,
    2102             :         }, /* PROT_AUTH_PACKET */
    2103             :         {
    2104             :                 sizeof(MYSQLND_PACKET_AUTH_RESPONSE),
    2105             :                 php_mysqlnd_auth_response_read, /* read */
    2106             :                 NULL, /* write */
    2107             :                 php_mysqlnd_auth_response_free_mem,
    2108             :         }, /* PROT_AUTH_RESP_PACKET */
    2109             :         {
    2110             :                 sizeof(MYSQLND_PACKET_CHANGE_AUTH_RESPONSE),
    2111             :                 NULL, /* read */
    2112             :                 php_mysqlnd_change_auth_response_write, /* write */
    2113             :                 php_mysqlnd_change_auth_response_free_mem,
    2114             :         }, /* PROT_CHANGE_AUTH_RESP_PACKET */
    2115             :         {
    2116             :                 sizeof(MYSQLND_PACKET_OK),
    2117             :                 php_mysqlnd_ok_read, /* read */
    2118             :                 NULL, /* write */
    2119             :                 php_mysqlnd_ok_free_mem,
    2120             :         }, /* PROT_OK_PACKET */
    2121             :         {
    2122             :                 sizeof(MYSQLND_PACKET_EOF),
    2123             :                 php_mysqlnd_eof_read, /* read */
    2124             :                 NULL, /* write */
    2125             :                 php_mysqlnd_eof_free_mem,
    2126             :         }, /* PROT_EOF_PACKET */
    2127             :         {
    2128             :                 sizeof(MYSQLND_PACKET_COMMAND),
    2129             :                 NULL, /* read */
    2130             :                 php_mysqlnd_cmd_write, /* write */
    2131             :                 php_mysqlnd_cmd_free_mem,
    2132             :         }, /* PROT_CMD_PACKET */
    2133             :         {
    2134             :                 sizeof(MYSQLND_PACKET_RSET_HEADER),
    2135             :                 php_mysqlnd_rset_header_read, /* read */
    2136             :                 NULL, /* write */
    2137             :                 php_mysqlnd_rset_header_free_mem,
    2138             :         }, /* PROT_RSET_HEADER_PACKET */
    2139             :         {
    2140             :                 sizeof(MYSQLND_PACKET_RES_FIELD),
    2141             :                 php_mysqlnd_rset_field_read, /* read */
    2142             :                 NULL, /* write */
    2143             :                 php_mysqlnd_rset_field_free_mem,
    2144             :         }, /* PROT_RSET_FLD_PACKET */
    2145             :         {
    2146             :                 sizeof(MYSQLND_PACKET_ROW),
    2147             :                 php_mysqlnd_rowp_read, /* read */
    2148             :                 NULL, /* write */
    2149             :                 php_mysqlnd_rowp_free_mem,
    2150             :         }, /* PROT_ROW_PACKET */
    2151             :         {
    2152             :                 sizeof(MYSQLND_PACKET_STATS),
    2153             :                 php_mysqlnd_stats_read, /* read */
    2154             :                 NULL, /* write */
    2155             :                 php_mysqlnd_stats_free_mem,
    2156             :         }, /* PROT_STATS_PACKET */
    2157             :         {
    2158             :                 sizeof(MYSQLND_PACKET_PREPARE_RESPONSE),
    2159             :                 php_mysqlnd_prepare_read, /* read */
    2160             :                 NULL, /* write */
    2161             :                 php_mysqlnd_prepare_free_mem,
    2162             :         }, /* PROT_PREPARE_RESP_PACKET */
    2163             :         {
    2164             :                 sizeof(MYSQLND_PACKET_CHG_USER_RESPONSE),
    2165             :                 php_mysqlnd_chg_user_read, /* read */
    2166             :                 NULL, /* write */
    2167             :                 php_mysqlnd_chg_user_free_mem,
    2168             :         } /* PROT_CHG_USER_RESP_PACKET */
    2169             : };
    2170             : /* }}} */
    2171             : 
    2172             : 
    2173             : /* {{{ mysqlnd_protocol::get_greet_packet */
    2174             : static struct st_mysqlnd_packet_greet *
    2175        1852 : MYSQLND_METHOD(mysqlnd_protocol, get_greet_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
    2176             : {
    2177        1852 :         struct st_mysqlnd_packet_greet * packet = mnd_pecalloc(1, packet_methods[PROT_GREET_PACKET].struct_size, persistent);
    2178        1852 :         DBG_ENTER("mysqlnd_protocol::get_greet_packet");
    2179        1852 :         if (packet) {
    2180        1852 :                 packet->header.m = &packet_methods[PROT_GREET_PACKET];
    2181        1852 :                 packet->header.persistent = persistent;
    2182             :         }
    2183        1852 :         DBG_RETURN(packet);
    2184             : }
    2185             : /* }}} */
    2186             : 
    2187             : 
    2188             : /* {{{ mysqlnd_protocol::get_auth_packet */
    2189             : static struct st_mysqlnd_packet_auth *
    2190        3740 : MYSQLND_METHOD(mysqlnd_protocol, get_auth_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
    2191             : {
    2192        3740 :         struct st_mysqlnd_packet_auth * packet = mnd_pecalloc(1, packet_methods[PROT_AUTH_PACKET].struct_size, persistent);
    2193        3740 :         DBG_ENTER("mysqlnd_protocol::get_auth_packet");
    2194        3740 :         if (packet) {
    2195        3740 :                 packet->header.m = &packet_methods[PROT_AUTH_PACKET];
    2196        3740 :                 packet->header.persistent = persistent;
    2197             :         }
    2198        3740 :         DBG_RETURN(packet);
    2199             : }
    2200             : /* }}} */
    2201             : 
    2202             : 
    2203             : /* {{{ mysqlnd_protocol::get_auth_response_packet */
    2204             : static struct st_mysqlnd_packet_auth_response *
    2205        1835 : MYSQLND_METHOD(mysqlnd_protocol, get_auth_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
    2206             : {
    2207        1835 :         struct st_mysqlnd_packet_auth_response * packet = mnd_pecalloc(1, packet_methods[PROT_AUTH_RESP_PACKET].struct_size, persistent);
    2208        1835 :         DBG_ENTER("mysqlnd_protocol::get_auth_response_packet");
    2209        1835 :         if (packet) {
    2210        1835 :                 packet->header.m = &packet_methods[PROT_AUTH_RESP_PACKET];
    2211        1835 :                 packet->header.persistent = persistent;
    2212             :         }
    2213        1835 :         DBG_RETURN(packet);
    2214             : }
    2215             : /* }}} */
    2216             : 
    2217             : 
    2218             : /* {{{ mysqlnd_protocol::get_change_auth_response_packet */
    2219             : static struct st_mysqlnd_packet_change_auth_response *
    2220           0 : MYSQLND_METHOD(mysqlnd_protocol, get_change_auth_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
    2221             : {
    2222           0 :         struct st_mysqlnd_packet_change_auth_response * packet = mnd_pecalloc(1, packet_methods[PROT_CHANGE_AUTH_RESP_PACKET].struct_size, persistent);
    2223           0 :         DBG_ENTER("mysqlnd_protocol::get_change_auth_response_packet");
    2224           0 :         if (packet) {
    2225           0 :                 packet->header.m = &packet_methods[PROT_CHANGE_AUTH_RESP_PACKET];
    2226           0 :                 packet->header.persistent = persistent;
    2227             :         }
    2228           0 :         DBG_RETURN(packet);
    2229             : }
    2230             : /* }}} */
    2231             : 
    2232             : 
    2233             : /* {{{ mysqlnd_protocol::get_ok_packet */
    2234             : static struct st_mysqlnd_packet_ok *
    2235         302 : MYSQLND_METHOD(mysqlnd_protocol, get_ok_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
    2236             : {
    2237         302 :         struct st_mysqlnd_packet_ok * packet = mnd_pecalloc(1, packet_methods[PROT_OK_PACKET].struct_size, persistent);
    2238         302 :         DBG_ENTER("mysqlnd_protocol::get_ok_packet");
    2239         302 :         if (packet) {
    2240         302 :                 packet->header.m = &packet_methods[PROT_OK_PACKET];
    2241         302 :                 packet->header.persistent = persistent;
    2242             :         }
    2243         302 :         DBG_RETURN(packet);
    2244             : }
    2245             : /* }}} */
    2246             : 
    2247             : 
    2248             : /* {{{ mysqlnd_protocol::get_eof_packet */
    2249             : static struct st_mysqlnd_packet_eof *
    2250        8018 : MYSQLND_METHOD(mysqlnd_protocol, get_eof_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
    2251             : {
    2252        8018 :         struct st_mysqlnd_packet_eof * packet = mnd_pecalloc(1, packet_methods[PROT_EOF_PACKET].struct_size, persistent);
    2253        8018 :         DBG_ENTER("mysqlnd_protocol::get_eof_packet");
    2254        8018 :         if (packet) {
    2255        8018 :                 packet->header.m = &packet_methods[PROT_EOF_PACKET];
    2256        8018 :                 packet->header.persistent = persistent;
    2257             :         }
    2258        8018 :         DBG_RETURN(packet);
    2259             : }
    2260             : /* }}} */
    2261             : 
    2262             : 
    2263             : /* {{{ mysqlnd_protocol::get_command_packet */
    2264             : static struct st_mysqlnd_packet_command *
    2265       36624 : MYSQLND_METHOD(mysqlnd_protocol, get_command_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
    2266             : {
    2267       36624 :         struct st_mysqlnd_packet_command * packet = mnd_pecalloc(1, packet_methods[PROT_CMD_PACKET].struct_size, persistent);
    2268       36624 :         DBG_ENTER("mysqlnd_protocol::get_command_packet");
    2269       36624 :         if (packet) {
    2270       36624 :                 packet->header.m = &packet_methods[PROT_CMD_PACKET];
    2271       36624 :                 packet->header.persistent = persistent;
    2272             :         }
    2273       36624 :         DBG_RETURN(packet);
    2274             : }
    2275             : /* }}} */
    2276             : 
    2277             : 
    2278             : /* {{{ mysqlnd_protocol::get_rset_packet */
    2279             : static struct st_mysqlnd_packet_rset_header *
    2280       25935 : MYSQLND_METHOD(mysqlnd_protocol, get_rset_header_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
    2281             : {
    2282       25935 :         struct st_mysqlnd_packet_rset_header * packet = mnd_pecalloc(1, packet_methods[PROT_RSET_HEADER_PACKET].struct_size, persistent);
    2283       25935 :         DBG_ENTER("mysqlnd_protocol::get_rset_header_packet");
    2284       25935 :         if (packet) {
    2285       25935 :                 packet->header.m = &packet_methods[PROT_RSET_HEADER_PACKET];
    2286       25935 :                 packet->header.persistent = persistent;
    2287             :         }
    2288       25935 :         DBG_RETURN(packet);
    2289             : }
    2290             : /* }}} */
    2291             : 
    2292             : 
    2293             : /* {{{ mysqlnd_protocol::get_result_field_packet */
    2294             : static struct st_mysqlnd_packet_res_field *
    2295        7888 : MYSQLND_METHOD(mysqlnd_protocol, get_result_field_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
    2296             : {
    2297        7888 :         struct st_mysqlnd_packet_res_field * packet = mnd_pecalloc(1, packet_methods[PROT_RSET_FLD_PACKET].struct_size, persistent);
    2298        7888 :         DBG_ENTER("mysqlnd_protocol::get_result_field_packet");
    2299        7888 :         if (packet) {
    2300        7888 :                 packet->header.m = &packet_methods[PROT_RSET_FLD_PACKET];
    2301        7888 :                 packet->header.persistent = persistent;
    2302             :         }
    2303        7888 :         DBG_RETURN(packet);
    2304             : }
    2305             : /* }}} */
    2306             : 
    2307             : 
    2308             : /* {{{ mysqlnd_protocol::get_row_packet */
    2309             : static struct st_mysqlnd_packet_row *
    2310        4623 : MYSQLND_METHOD(mysqlnd_protocol, get_row_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
    2311             : {
    2312        4623 :         struct st_mysqlnd_packet_row * packet = mnd_pecalloc(1, packet_methods[PROT_ROW_PACKET].struct_size, persistent);
    2313        4623 :         DBG_ENTER("mysqlnd_protocol::get_row_packet");
    2314        4623 :         if (packet) {
    2315        4623 :                 packet->header.m = &packet_methods[PROT_ROW_PACKET];
    2316        4623 :                 packet->header.persistent = persistent;
    2317             :         }
    2318        4623 :         DBG_RETURN(packet);
    2319             : }
    2320             : /* }}} */
    2321             : 
    2322             : 
    2323             : /* {{{ mysqlnd_protocol::get_stats_packet */
    2324             : static struct st_mysqlnd_packet_stats *
    2325          16 : MYSQLND_METHOD(mysqlnd_protocol, get_stats_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
    2326             : {
    2327          16 :         struct st_mysqlnd_packet_stats * packet = mnd_pecalloc(1, packet_methods[PROT_STATS_PACKET].struct_size, persistent);
    2328          16 :         DBG_ENTER("mysqlnd_protocol::get_stats_packet");
    2329          16 :         if (packet) {
    2330          16 :                 packet->header.m = &packet_methods[PROT_STATS_PACKET];
    2331          16 :                 packet->header.persistent = persistent;
    2332             :         }
    2333          16 :         DBG_RETURN(packet);
    2334             : }
    2335             : /* }}} */
    2336             : 
    2337             : 
    2338             : /* {{{ mysqlnd_protocol::get_prepare_response_packet */
    2339             : static struct st_mysqlnd_packet_prepare_response *
    2340        4240 : MYSQLND_METHOD(mysqlnd_protocol, get_prepare_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
    2341             : {
    2342        4240 :         struct st_mysqlnd_packet_prepare_response * packet = mnd_pecalloc(1, packet_methods[PROT_PREPARE_RESP_PACKET].struct_size, persistent);
    2343        4240 :         DBG_ENTER("mysqlnd_protocol::get_prepare_response_packet");
    2344        4240 :         if (packet) {
    2345        4240 :                 packet->header.m = &packet_methods[PROT_PREPARE_RESP_PACKET];
    2346        4240 :                 packet->header.persistent = persistent;
    2347             :         }
    2348        4240 :         DBG_RETURN(packet);
    2349             : }
    2350             : /* }}} */
    2351             : 
    2352             : 
    2353             : /* {{{ mysqlnd_protocol::get_change_user_response_packet */
    2354             : static struct st_mysqlnd_packet_chg_user_resp*
    2355          67 : MYSQLND_METHOD(mysqlnd_protocol, get_change_user_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
    2356             : {
    2357          67 :         struct st_mysqlnd_packet_chg_user_resp * packet = mnd_pecalloc(1, packet_methods[PROT_CHG_USER_RESP_PACKET].struct_size, persistent);
    2358          67 :         DBG_ENTER("mysqlnd_protocol::get_change_user_response_packet");
    2359          67 :         if (packet) {
    2360          67 :                 packet->header.m = &packet_methods[PROT_CHG_USER_RESP_PACKET];
    2361          67 :                 packet->header.persistent = persistent;
    2362             :         }
    2363          67 :         DBG_RETURN(packet);
    2364             : }
    2365             : /* }}} */
    2366             : 
    2367             : 
    2368             : MYSQLND_CLASS_METHODS_START(mysqlnd_protocol)
    2369             :         MYSQLND_METHOD(mysqlnd_protocol, get_greet_packet),
    2370             :         MYSQLND_METHOD(mysqlnd_protocol, get_auth_packet),
    2371             :         MYSQLND_METHOD(mysqlnd_protocol, get_auth_response_packet),
    2372             :         MYSQLND_METHOD(mysqlnd_protocol, get_change_auth_response_packet),
    2373             :         MYSQLND_METHOD(mysqlnd_protocol, get_ok_packet),
    2374             :         MYSQLND_METHOD(mysqlnd_protocol, get_command_packet),
    2375             :         MYSQLND_METHOD(mysqlnd_protocol, get_eof_packet),
    2376             :         MYSQLND_METHOD(mysqlnd_protocol, get_rset_header_packet),
    2377             :         MYSQLND_METHOD(mysqlnd_protocol, get_result_field_packet),
    2378             :         MYSQLND_METHOD(mysqlnd_protocol, get_row_packet),
    2379             :         MYSQLND_METHOD(mysqlnd_protocol, get_stats_packet),
    2380             :         MYSQLND_METHOD(mysqlnd_protocol, get_prepare_response_packet),
    2381             :         MYSQLND_METHOD(mysqlnd_protocol, get_change_user_response_packet)
    2382             : MYSQLND_CLASS_METHODS_END;
    2383             : 
    2384             : 
    2385             : /* {{{ mysqlnd_protocol_init */
    2386             : PHPAPI MYSQLND_PROTOCOL *
    2387        1915 : mysqlnd_protocol_init(zend_bool persistent TSRMLS_DC)
    2388             : {
    2389             :         MYSQLND_PROTOCOL * ret;
    2390        1915 :         DBG_ENTER("mysqlnd_protocol_init");
    2391        1915 :         ret = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory).get_protocol_decoder(persistent TSRMLS_CC);
    2392        1915 :         DBG_RETURN(ret);
    2393             : }
    2394             : /* }}} */
    2395             : 
    2396             : 
    2397             : /* {{{ mysqlnd_protocol_free */
    2398             : PHPAPI void
    2399        1876 : mysqlnd_protocol_free(MYSQLND_PROTOCOL * const protocol TSRMLS_DC)
    2400             : {
    2401        1876 :         DBG_ENTER("mysqlnd_protocol_free");
    2402             : 
    2403        1876 :         if (protocol) {
    2404        1876 :                 zend_bool pers = protocol->persistent;
    2405        1876 :                 mnd_pefree(protocol, pers);
    2406             :         }
    2407        1876 :         DBG_VOID_RETURN;
    2408             : }
    2409             : /* }}} */
    2410             : 
    2411             : 
    2412             : /*
    2413             :  * Local variables:
    2414             :  * tab-width: 4
    2415             :  * c-basic-offset: 4
    2416             :  * End:
    2417             :  * vim600: noet sw=4 ts=4 fdm=marker
    2418             :  * vim<600: noet sw=4 ts=4
    2419             :  */

Generated by: LCOV version 1.10

Generated at Sun, 21 Sep 2014 15:27:39 +0000 (14 hours ago)

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