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

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

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