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

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