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

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

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