root/ext/mysqlnd/mysqlnd_wireprotocol.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_mysqlnd_net_field_length
  2. php_mysqlnd_net_field_length_ll
  3. php_mysqlnd_net_store_length
  4. php_mysqlnd_net_store_length_size
  5. php_mysqlnd_read_error_from_line
  6. mysqlnd_read_header
  7. php_mysqlnd_greet_read
  8. php_mysqlnd_greet_free_mem
  9. php_mysqlnd_auth_write
  10. php_mysqlnd_auth_free_mem
  11. php_mysqlnd_auth_response_read
  12. php_mysqlnd_auth_response_free_mem
  13. php_mysqlnd_change_auth_response_write
  14. php_mysqlnd_change_auth_response_free_mem
  15. php_mysqlnd_ok_read
  16. php_mysqlnd_ok_free_mem
  17. php_mysqlnd_eof_read
  18. php_mysqlnd_eof_free_mem
  19. php_mysqlnd_cmd_write
  20. php_mysqlnd_cmd_free_mem
  21. php_mysqlnd_rset_header_read
  22. php_mysqlnd_rset_header_free_mem
  23. php_mysqlnd_rset_field_read
  24. php_mysqlnd_rset_field_free_mem
  25. php_mysqlnd_read_row_ex
  26. php_mysqlnd_rowp_read_binary_protocol
  27. php_mysqlnd_rowp_read_text_protocol_aux
  28. php_mysqlnd_rowp_read_text_protocol_zval
  29. php_mysqlnd_rowp_read_text_protocol_c
  30. php_mysqlnd_rowp_read
  31. php_mysqlnd_rowp_free_mem
  32. php_mysqlnd_stats_read
  33. php_mysqlnd_stats_free_mem
  34. php_mysqlnd_prepare_read
  35. php_mysqlnd_prepare_free_mem
  36. php_mysqlnd_chg_user_read
  37. php_mysqlnd_chg_user_free_mem
  38. php_mysqlnd_sha256_pk_request_write
  39. php_mysqlnd_sha256_pk_request_free_mem
  40. php_mysqlnd_sha256_pk_request_response_read
  41. php_mysqlnd_sha256_pk_request_response_free_mem
  42. MYSQLND_CLASS_METHODS_START
  43. mysqlnd_protocol_free

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

/* [<][>][^][v][top][bottom][index][help] */