Annotation of embedaddon/php/ext/mysqlnd/mysqlnd_wireprotocol.c, revision 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>