Annotation of embedaddon/php/ext/mysqlnd/mysqlnd_wireprotocol.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>