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

1.1       misho       1: /*
                      2:   +----------------------------------------------------------------------+
                      3:   | PHP Version 5                                                        |
                      4:   +----------------------------------------------------------------------+
                      5:   | Copyright (c) 2006-2012 The PHP Group                                |
                      6:   +----------------------------------------------------------------------+
                      7:   | This source file is subject to version 3.01 of the PHP license,      |
                      8:   | that is bundled with this package in the file LICENSE, and is        |
                      9:   | available through the world-wide-web at the following url:           |
                     10:   | http://www.php.net/license/3_01.txt                                  |
                     11:   | If you did not receive a copy of the PHP license and are unable to   |
                     12:   | obtain it through the world-wide-web, please send a note to          |
                     13:   | license@php.net so we can mail you a copy immediately.               |
                     14:   +----------------------------------------------------------------------+
                     15:   | Authors: Georg Richter <georg@mysql.com>                             |
                     16:   |          Andrey Hristov <andrey@mysql.com>                           |
                     17:   |          Ulf Wendel <uwendel@mysql.com>                              |
                     18:   +----------------------------------------------------------------------+
                     19: */
                     20: 
                     21: /* $Id: mysqlnd.c 321634 2012-01-01 13:15:04Z felipe $ */
                     22: #include "php.h"
                     23: #include "mysqlnd.h"
                     24: #include "mysqlnd_wireprotocol.h"
                     25: #include "mysqlnd_priv.h"
                     26: #include "mysqlnd_result.h"
                     27: #include "mysqlnd_statistics.h"
                     28: #include "mysqlnd_charset.h"
                     29: #include "mysqlnd_debug.h"
                     30: /* for php_get_current_user() */
                     31: #include "ext/standard/basic_functions.h"
                     32: 
                     33: /*
                     34:   TODO :
                     35:   - Don't bind so tightly the metadata with the result set. This means
                     36:        that the metadata reading should not expect a MYSQLND_RES pointer, it
                     37:        does not need it, but return a pointer to the metadata (MYSQLND_FIELD *).
                     38:        For normal statements we will then just assign it to a member of
                     39:        MYSQLND_RES. For PS statements, it will stay as part of the statement
                     40:        (MYSQLND_STMT) between prepare and execute. At execute the new metadata
                     41:        will be sent by the server, so we will discard the old one and then
                     42:        finally attach it to the result set. This will make the code more clean,
                     43:        as a prepared statement won't have anymore stmt->result != NULL, as it
                     44:        is now, just to have where to store the metadata.
                     45: 
                     46:   - Change mysqlnd_simple_command to accept a heap dynamic array of MYSQLND_STRING
                     47:        terminated by a string with ptr being NULL. Thus, multi-part messages can be
                     48:        sent to the network like writev() and this can save at least for
                     49:        mysqlnd_stmt_send_long_data() new malloc. This change will probably make the
                     50:        code in few other places cleaner.
                     51: */
                     52: 
                     53: extern MYSQLND_CHARSET *mysqlnd_charsets;
                     54: 
                     55: 
                     56: 
                     57: PHPAPI const char * const mysqlnd_old_passwd  = "mysqlnd cannot connect to MySQL 4.1+ using the old insecure authentication. "
                     58: "Please use an administration tool to reset your password with the command SET PASSWORD = PASSWORD('your_existing_password'). This will "
                     59: "store a new, and more secure, hash value in mysql.user. If this user is used in other scripts executed by PHP 5.2 or earlier you might need to remove the old-passwords "
                     60: "flag from your my.cnf file";
                     61: 
                     62: PHPAPI const char * const mysqlnd_server_gone = "MySQL server has gone away";
                     63: PHPAPI const char * const mysqlnd_out_of_sync = "Commands out of sync; you can't run this command now";
                     64: PHPAPI const char * const mysqlnd_out_of_memory = "Out of memory";
                     65: 
                     66: PHPAPI MYSQLND_STATS *mysqlnd_global_stats = NULL;
                     67: static zend_bool mysqlnd_library_initted = FALSE;
                     68: 
                     69: static struct st_mysqlnd_conn_methods *mysqlnd_conn_methods;
                     70: 
                     71: /* {{{ mysqlnd_library_end */
                     72: PHPAPI void mysqlnd_library_end(TSRMLS_D)
                     73: {
                     74:        if (mysqlnd_library_initted == TRUE) {
                     75:                mysqlnd_stats_end(mysqlnd_global_stats);
                     76:                mysqlnd_global_stats = NULL;
                     77:                mysqlnd_library_initted = FALSE;
                     78:        }
                     79: }
                     80: /* }}} */
                     81: 
                     82: 
                     83: /* {{{ mysqlnd_conn::free_options */
                     84: static void
                     85: MYSQLND_METHOD(mysqlnd_conn, free_options)(MYSQLND * conn TSRMLS_DC)
                     86: {
                     87:        zend_bool pers = conn->persistent;
                     88: 
                     89:        if (conn->options.charset_name) {
                     90:                mnd_pefree(conn->options.charset_name, pers);
                     91:                conn->options.charset_name = NULL;
                     92:        }
                     93:        if (conn->options.num_commands) {
                     94:                unsigned int i;
                     95:                for (i = 0; i < conn->options.num_commands; i++) {
                     96:                        /* allocated with pestrdup */
                     97:                        mnd_pefree(conn->options.init_commands[i], pers);
                     98:                }
                     99:                mnd_pefree(conn->options.init_commands, pers);
                    100:                conn->options.init_commands = NULL;
                    101:        }
                    102:        if (conn->options.cfg_file) {
                    103:                mnd_pefree(conn->options.cfg_file, pers);
                    104:                conn->options.cfg_file = NULL;
                    105:        }
                    106:        if (conn->options.cfg_section) {
                    107:                mnd_pefree(conn->options.cfg_section, pers);
                    108:                conn->options.cfg_section = NULL;
                    109:        }
                    110: }
                    111: /* }}} */
                    112: 
                    113: 
                    114: /* {{{ mysqlnd_conn::free_contents */
                    115: static void
                    116: MYSQLND_METHOD(mysqlnd_conn, free_contents)(MYSQLND * conn TSRMLS_DC)
                    117: {
                    118:        zend_bool pers = conn->persistent;
                    119: 
                    120:        DBG_ENTER("mysqlnd_conn::free_contents");
                    121: 
                    122:        mysqlnd_local_infile_default(conn);
                    123:        if (conn->current_result) {
                    124:                conn->current_result->m.free_result(conn->current_result, TRUE TSRMLS_CC);
                    125:                conn->current_result = NULL;
                    126:        }
                    127: 
                    128:        if (conn->net) {
                    129:                conn->net->m.free_contents(conn->net TSRMLS_CC);
                    130:        }
                    131: 
                    132:        DBG_INF("Freeing memory of members");
                    133: 
                    134:        if (conn->host) {
                    135:                DBG_INF("Freeing host");
                    136:                mnd_pefree(conn->host, pers);
                    137:                conn->host = NULL;
                    138:        }
                    139:        if (conn->user) {
                    140:                DBG_INF("Freeing user");
                    141:                mnd_pefree(conn->user, pers);
                    142:                conn->user = NULL;
                    143:        }
                    144:        if (conn->passwd) {
                    145:                DBG_INF("Freeing passwd");
                    146:                mnd_pefree(conn->passwd, pers);
                    147:                conn->passwd = NULL;
                    148:        }
                    149:        if (conn->connect_or_select_db) {
                    150:                DBG_INF("Freeing connect_or_select_db");
                    151:                mnd_pefree(conn->connect_or_select_db, pers);
                    152:                conn->connect_or_select_db = NULL;
                    153:        }
                    154:        if (conn->unix_socket) {
                    155:                DBG_INF("Freeing unix_socket");
                    156:                mnd_pefree(conn->unix_socket, pers);
                    157:                conn->unix_socket = NULL;
                    158:        }
                    159:        DBG_INF_FMT("scheme=%s", conn->scheme);
                    160:        if (conn->scheme) {
                    161:                DBG_INF("Freeing scheme");
                    162:                mnd_pefree(conn->scheme, pers);
                    163:                conn->scheme = NULL;
                    164:        }
                    165:        if (conn->server_version) {
                    166:                DBG_INF("Freeing server_version");
                    167:                mnd_pefree(conn->server_version, pers);
                    168:                conn->server_version = NULL;
                    169:        }
                    170:        if (conn->host_info) {
                    171:                DBG_INF("Freeing host_info");
                    172:                mnd_pefree(conn->host_info, pers);
                    173:                conn->host_info = NULL;
                    174:        }
                    175:        if (conn->scramble) {
                    176:                DBG_INF("Freeing scramble");
                    177:                mnd_pefree(conn->scramble, pers);
                    178:                conn->scramble = NULL;
                    179:        }
                    180:        if (conn->last_message) {
                    181:                mnd_pefree(conn->last_message, pers);
                    182:                conn->last_message = NULL;
                    183:        }
                    184:        conn->charset = NULL;
                    185:        conn->greet_charset = NULL;
                    186: 
                    187:        DBG_VOID_RETURN;
                    188: }
                    189: /* }}} */
                    190: 
                    191: 
                    192: /* {{{ mysqlnd_conn::dtor */
                    193: static void
                    194: MYSQLND_METHOD_PRIVATE(mysqlnd_conn, dtor)(MYSQLND * conn TSRMLS_DC)
                    195: {
                    196:        DBG_ENTER("mysqlnd_conn::dtor");
                    197:        DBG_INF_FMT("conn=%llu", conn->thread_id);
                    198: 
                    199:        conn->m->free_contents(conn TSRMLS_CC);
                    200:        conn->m->free_options(conn TSRMLS_CC);
                    201: 
                    202:        if (conn->net) {
                    203:                DBG_INF("Freeing net");
                    204:                mysqlnd_net_free(conn->net TSRMLS_CC);
                    205:                conn->net = NULL;
                    206:        }
                    207: 
                    208:        if (conn->protocol) {
                    209:                DBG_INF("Freeing protocol");
                    210:                mysqlnd_protocol_free(conn->protocol TSRMLS_CC);
                    211:                conn->protocol = NULL;
                    212:        }
                    213: 
                    214:        if (conn->stats) {
                    215:                mysqlnd_stats_end(conn->stats);
                    216:        }
                    217: 
                    218:        mnd_pefree(conn, conn->persistent);
                    219: 
                    220:        DBG_VOID_RETURN;
                    221: }
                    222: /* }}} */
                    223: 
                    224: 
                    225: /* {{{ mysqlnd_conn::simple_command_handle_response */
                    226: static enum_func_status
                    227: MYSQLND_METHOD(mysqlnd_conn, simple_command_handle_response)(MYSQLND * conn, enum mysqlnd_packet_type ok_packet,
                    228:                                                                                                                         zend_bool silent, enum php_mysqlnd_server_command command,
                    229:                                                                                                                         zend_bool ignore_upsert_status TSRMLS_DC)
                    230: {
                    231:        enum_func_status ret = FAIL;
                    232: 
                    233:        DBG_ENTER("mysqlnd_conn::simple_command_handle_response");
                    234:        DBG_INF_FMT("silent=%u packet=%u command=%s", silent, ok_packet, mysqlnd_command_to_text[command]);
                    235: 
                    236:        switch (ok_packet) {
                    237:                case PROT_OK_PACKET:{
                    238:                        MYSQLND_PACKET_OK * ok_response = conn->protocol->m.get_ok_packet(conn->protocol, FALSE TSRMLS_CC);
                    239:                        if (!ok_response) {
                    240:                                SET_OOM_ERROR(conn->error_info);
                    241:                                break;
                    242:                        }
                    243:                        if (FAIL == (ret = PACKET_READ(ok_response, conn))) {
                    244:                                if (!silent) {
                    245:                                        DBG_ERR_FMT("Error while reading %s's OK packet", mysqlnd_command_to_text[command]);
                    246:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading %s's OK packet. PID=%u",
                    247:                                                                         mysqlnd_command_to_text[command], getpid());
                    248:                                }
                    249:                        } else {
                    250:                                DBG_INF_FMT("OK from server");
                    251:                                if (0xFF == ok_response->field_count) {
                    252:                                        /* The server signalled error. Set the error */
                    253:                                        SET_CLIENT_ERROR(conn->error_info, ok_response->error_no, ok_response->sqlstate, ok_response->error);
                    254:                                        ret = FAIL;
                    255:                                        /*
                    256:                                          Cover a protocol design error: error packet does not
                    257:                                          contain the server status. Therefore, the client has no way
                    258:                                          to find out whether there are more result sets of
                    259:                                          a multiple-result-set statement pending. Luckily, in 5.0 an
                    260:                                          error always aborts execution of a statement, wherever it is
                    261:                                          a multi-statement or a stored procedure, so it should be
                    262:                                          safe to unconditionally turn off the flag here.
                    263:                                        */
                    264:                                        conn->upsert_status.server_status &= ~SERVER_MORE_RESULTS_EXISTS;
                    265:                                        SET_ERROR_AFF_ROWS(conn);
                    266:                                } else {
                    267:                                        SET_NEW_MESSAGE(conn->last_message, conn->last_message_len,
                    268:                                                                        ok_response->message, ok_response->message_len,
                    269:                                                                        conn->persistent);
                    270: 
                    271:                                        if (!ignore_upsert_status) {
                    272:                                                conn->upsert_status.warning_count = ok_response->warning_count;
                    273:                                                conn->upsert_status.server_status = ok_response->server_status;
                    274:                                                conn->upsert_status.affected_rows = ok_response->affected_rows;
                    275:                                                conn->upsert_status.last_insert_id = ok_response->last_insert_id;
                    276:                                        }
                    277:                                }
                    278:                        }
                    279:                        PACKET_FREE(ok_response);
                    280:                        break;
                    281:                }
                    282:                case PROT_EOF_PACKET:{
                    283:                        MYSQLND_PACKET_EOF * ok_response = conn->protocol->m.get_eof_packet(conn->protocol, FALSE TSRMLS_CC);
                    284:                        if (!ok_response) {
                    285:                                SET_OOM_ERROR(conn->error_info);
                    286:                                break;
                    287:                        }
                    288:                        if (FAIL == (ret = PACKET_READ(ok_response, conn))) {
                    289:                                SET_CLIENT_ERROR(conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE,
                    290:                                                                 "Malformed packet");
                    291:                                if (!silent) {
                    292:                                        DBG_ERR_FMT("Error while reading %s's EOF packet", mysqlnd_command_to_text[command]);
                    293:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading %s's EOF packet. PID=%d",
                    294:                                                                         mysqlnd_command_to_text[command], getpid());
                    295:                                }
                    296:                        } else if (0xFF == ok_response->field_count) {
                    297:                                /* The server signalled error. Set the error */
                    298:                                SET_CLIENT_ERROR(conn->error_info, ok_response->error_no, ok_response->sqlstate, ok_response->error);
                    299:                                SET_ERROR_AFF_ROWS(conn);
                    300:                        } else if (0xFE != ok_response->field_count) {
                    301:                                SET_CLIENT_ERROR(conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet");
                    302:                                if (!silent) {
                    303:                                        DBG_ERR_FMT("EOF packet expected, field count wasn't 0xFE but 0x%2X", ok_response->field_count);
                    304:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "EOF packet expected, field count wasn't 0xFE but 0x%2X",
                    305:                                                                        ok_response->field_count);
                    306:                                }
                    307:                        } else {
                    308:                                DBG_INF_FMT("OK from server");
                    309:                        }
                    310:                        PACKET_FREE(ok_response);
                    311:                        break;
                    312:                }
                    313:                default:
                    314:                        SET_CLIENT_ERROR(conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet");
                    315:                        php_error_docref(NULL TSRMLS_CC, E_ERROR, "Wrong response packet %u passed to the function", ok_packet);
                    316:                        break;
                    317:        }
                    318:        DBG_INF(ret == PASS ? "PASS":"FAIL");
                    319:        DBG_RETURN(ret);
                    320: }
                    321: /* }}} */
                    322: 
                    323: 
                    324: /* {{{ mysqlnd_conn::simple_command */
                    325: static enum_func_status
                    326: MYSQLND_METHOD(mysqlnd_conn, simple_command)(MYSQLND * conn, enum php_mysqlnd_server_command command,
                    327:                           const char * const arg, size_t arg_len, enum mysqlnd_packet_type ok_packet, zend_bool silent,
                    328:                           zend_bool ignore_upsert_status TSRMLS_DC)
                    329: {
                    330:        enum_func_status ret = PASS;
                    331:        MYSQLND_PACKET_COMMAND * cmd_packet;
                    332: 
                    333:        DBG_ENTER("mysqlnd_conn::simple_command");
                    334:        DBG_INF_FMT("command=%s ok_packet=%u silent=%u", mysqlnd_command_to_text[command], ok_packet, silent);
                    335: 
                    336:        switch (CONN_GET_STATE(conn)) {
                    337:                case CONN_READY:
                    338:                        break;
                    339:                case CONN_QUIT_SENT:
                    340:                        SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
                    341:                        DBG_ERR("Server is gone");
                    342:                        DBG_RETURN(FAIL);
                    343:                default:
                    344:                        SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
                    345:                        DBG_ERR_FMT("Command out of sync. State=%u", CONN_GET_STATE(conn));
                    346:                        DBG_RETURN(FAIL);
                    347:        }
                    348: 
                    349:        /* clean UPSERT info */
                    350:        if (!ignore_upsert_status) {
                    351:                memset(&conn->upsert_status, 0, sizeof(conn->upsert_status));
                    352:        }
                    353:        SET_ERROR_AFF_ROWS(conn);
                    354:        SET_EMPTY_ERROR(conn->error_info);
                    355: 
                    356:        cmd_packet = conn->protocol->m.get_command_packet(conn->protocol, FALSE TSRMLS_CC);
                    357:        if (!cmd_packet) {
                    358:                SET_OOM_ERROR(conn->error_info);
                    359:                DBG_RETURN(FAIL);
                    360:        }
                    361: 
                    362:        cmd_packet->command = command;
                    363:        if (arg && arg_len) {
                    364:                cmd_packet->argument = arg;
                    365:                cmd_packet->arg_len  = arg_len;
                    366:        }
                    367: 
                    368:        MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_COM_QUIT + command - 1 /* because of COM_SLEEP */ );
                    369: 
                    370:        if (! PACKET_WRITE(cmd_packet, conn)) {
                    371:                if (!silent) {
                    372:                        DBG_ERR_FMT("Error while sending %s packet", mysqlnd_command_to_text[command]);
                    373:                        php_error(E_WARNING, "Error while sending %s packet. PID=%d", mysqlnd_command_to_text[command], getpid());
                    374:                }
                    375:                DBG_ERR("Server is gone");
                    376:                ret = FAIL;
                    377:        } else if (ok_packet != PROT_LAST) {
                    378:                ret = conn->m->simple_command_handle_response(conn, ok_packet, silent, command, ignore_upsert_status TSRMLS_CC);
                    379:        }
                    380: 
                    381:        PACKET_FREE(cmd_packet);
                    382:        DBG_INF(ret == PASS ? "PASS":"FAIL");
                    383:        DBG_RETURN(ret);
                    384: }
                    385: /* }}} */
                    386: 
                    387: 
                    388: /* {{{ mysqlnd_conn::set_server_option */
                    389: static enum_func_status
                    390: MYSQLND_METHOD(mysqlnd_conn, set_server_option)(MYSQLND * const conn, enum_mysqlnd_server_option option TSRMLS_DC)
                    391: {
                    392:        enum_func_status ret;
                    393:        char buffer[2];
                    394:        DBG_ENTER("mysqlnd_conn::set_server_option");
                    395: 
                    396:        int2store(buffer, (unsigned int) option);
                    397:        ret = conn->m->simple_command(conn, COM_SET_OPTION, buffer, sizeof(buffer), PROT_EOF_PACKET, FALSE, TRUE TSRMLS_CC);
                    398:        DBG_RETURN(ret);
                    399: }
                    400: /* }}} */
                    401: 
                    402: 
                    403: /* {{{ mysqlnd_conn::restart_psession */
                    404: static enum_func_status
                    405: MYSQLND_METHOD(mysqlnd_conn, restart_psession)(MYSQLND * conn TSRMLS_DC)
                    406: {
                    407:        DBG_ENTER("mysqlnd_conn::restart_psession");
                    408:        MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CONNECT_REUSED);
                    409:        /* Free here what should not be seen by the next script */
                    410:        if (conn->last_message) {
                    411:                mnd_pefree(conn->last_message, conn->persistent);
                    412:                conn->last_message = NULL;
                    413:        }
                    414:        DBG_RETURN(PASS);
                    415: }
                    416: /* }}} */
                    417: 
                    418: 
                    419: /* {{{ mysqlnd_conn::end_psession */
                    420: static enum_func_status
                    421: MYSQLND_METHOD(mysqlnd_conn, end_psession)(MYSQLND * conn TSRMLS_DC)
                    422: {
                    423:        DBG_ENTER("mysqlnd_conn::end_psession");
                    424:        DBG_RETURN(PASS);
                    425: }
                    426: /* }}} */
                    427: 
                    428: 
                    429: #define MYSQLND_ASSEBLED_PACKET_MAX_SIZE 3UL*1024UL*1024UL*1024UL
                    430: /* {{{ mysqlnd_connect_run_authentication */
                    431: static enum_func_status
                    432: mysqlnd_connect_run_authentication(
                    433:                        MYSQLND * conn,
                    434:                        const char * const user,
                    435:                        const char * const passwd,
                    436:                        const char * const db,
                    437:                        size_t db_len,
                    438:                        const MYSQLND_PACKET_GREET * const greet_packet,
                    439:                        const MYSQLND_OPTIONS * const options,
                    440:                        unsigned long mysql_flags
                    441:                        TSRMLS_DC)
                    442: {
                    443:        const MYSQLND_CHARSET * charset = NULL;
                    444:        enum_func_status ret = FAIL;
                    445:        MYSQLND_PACKET_AUTH * auth_packet = conn->protocol->m.get_auth_packet(conn->protocol, FALSE TSRMLS_CC);
                    446:        MYSQLND_PACKET_OK * ok_packet = conn->protocol->m.get_ok_packet(conn->protocol, FALSE TSRMLS_CC);
                    447: 
                    448:        DBG_ENTER("mysqlnd_connect_run_authentication");
                    449: 
                    450:        if (!auth_packet || !ok_packet) {
                    451:                SET_OOM_ERROR(conn->error_info);
                    452:                goto err;
                    453:        }
                    454: 
                    455: #ifdef MYSQLND_SSL_SUPPORTED
                    456:        if ((greet_packet->server_capabilities & CLIENT_SSL) && (mysql_flags & CLIENT_SSL)) {
                    457:                auth_packet->send_half_packet = TRUE;
                    458:        }
                    459: #endif
                    460:        auth_packet->user               = user;
                    461:        auth_packet->password   = passwd;
                    462: 
                    463:        if (options->charset_name && (charset = mysqlnd_find_charset_name(options->charset_name))) {
                    464:                auth_packet->charset_no = charset->nr;
                    465:        } else {
                    466: #if MYSQLND_UNICODE
                    467:                auth_packet->charset_no = 200;/* utf8 - swedish collation, check mysqlnd_charset.c */
                    468: #else
                    469:                auth_packet->charset_no = greet_packet->charset_no;
                    470: #endif
                    471:        }
                    472:        auth_packet->db                 = db;
                    473:        auth_packet->db_len             = db_len;
                    474:        auth_packet->max_packet_size= MYSQLND_ASSEBLED_PACKET_MAX_SIZE;
                    475:        auth_packet->client_flags= mysql_flags;
                    476: 
                    477:        conn->scramble = auth_packet->server_scramble_buf = mnd_pemalloc(SCRAMBLE_LENGTH, conn->persistent);
                    478:        if (!conn->scramble) {
                    479:                SET_OOM_ERROR(conn->error_info);
                    480:                goto err;
                    481:        }
                    482:        memcpy(auth_packet->server_scramble_buf, greet_packet->scramble_buf, SCRAMBLE_LENGTH);
                    483: 
                    484:        if (!PACKET_WRITE(auth_packet, conn)) {
                    485:                CONN_SET_STATE(conn, CONN_QUIT_SENT);
                    486:                SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
                    487:                goto err;
                    488:        }
                    489: 
                    490: #ifdef MYSQLND_SSL_SUPPORTED
                    491:        if (auth_packet->send_half_packet) {
                    492:                zend_bool verify = mysql_flags & CLIENT_SSL_VERIFY_SERVER_CERT? TRUE:FALSE;
                    493:                DBG_INF("Switching to SSL");
                    494: 
                    495:                conn->net->m.set_client_option(conn->net, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (const char *) &verify TSRMLS_CC);
                    496: 
                    497:                if (FAIL == conn->net->m.enable_ssl(conn->net TSRMLS_CC)) {
                    498:                        goto err;
                    499:                }
                    500: 
                    501:                auth_packet->send_half_packet = FALSE;
                    502:                if (!PACKET_WRITE(auth_packet, conn)) {
                    503:                        CONN_SET_STATE(conn, CONN_QUIT_SENT);
                    504:                        SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
                    505:                        goto err;
                    506:                }
                    507:        }
                    508: #endif
                    509: 
                    510: 
                    511:        if (FAIL == PACKET_READ(ok_packet, conn) || ok_packet->field_count >= 0xFE) {
                    512:                if (ok_packet->field_count == 0xFE) {
                    513:                        /* old authentication with new server  !*/
                    514:                        DBG_ERR(mysqlnd_old_passwd);
                    515:                        SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd);
                    516:                } else if (ok_packet->field_count == 0xFF) {
                    517:                        if (ok_packet->sqlstate[0]) {
                    518:                                strlcpy(conn->error_info.sqlstate, ok_packet->sqlstate, sizeof(conn->error_info.sqlstate));
                    519:                                DBG_ERR_FMT("ERROR:%u [SQLSTATE:%s] %s", ok_packet->error_no, ok_packet->sqlstate, ok_packet->error);
                    520:                        }
                    521:                        conn->error_info.error_no = ok_packet->error_no;
                    522:                        strlcpy(conn->error_info.error, ok_packet->error, sizeof(conn->error_info.error));
                    523:                }
                    524:                goto err;
                    525:        }
                    526: 
                    527:        SET_NEW_MESSAGE(conn->last_message, conn->last_message_len,
                    528:                                        ok_packet->message, ok_packet->message_len,
                    529:                                        conn->persistent);
                    530:        conn->charset = mysqlnd_find_charset_nr(auth_packet->charset_no);
                    531:        ret = PASS;
                    532: err:
                    533:        PACKET_FREE(auth_packet);
                    534:        PACKET_FREE(ok_packet);
                    535:        DBG_RETURN(ret);
                    536: }
                    537: /* }}} */
                    538: 
                    539: 
                    540: #define MYSQLND_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_TRANSACTIONS | \
                    541:                                CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION | \
                    542:                                CLIENT_MULTI_RESULTS)
                    543: 
                    544: 
                    545: 
                    546: /* {{{ mysqlnd_conn::connect */
                    547: static enum_func_status
                    548: MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn,
                    549:                                                 const char *host, const char *user,
                    550:                                                 const char *passwd, unsigned int passwd_len,
                    551:                                                 const char *db, unsigned int db_len,
                    552:                                                 unsigned int port,
                    553:                                                 const char * socket_or_pipe,
                    554:                                                 unsigned int mysql_flags
                    555:                                                 TSRMLS_DC)
                    556: {
                    557:        char *errstr = NULL;
                    558:        int errcode = 0, host_len;
                    559:        zend_bool unix_socket = FALSE;
                    560:        zend_bool reconnect = FALSE;
                    561:        zend_bool saved_compression = FALSE;
                    562: 
                    563:        MYSQLND_PACKET_GREET * greet_packet = NULL;
                    564: 
                    565:        DBG_ENTER("mysqlnd_conn::connect");
                    566: 
                    567:        DBG_INF_FMT("host=%s user=%s db=%s port=%u flags=%u persistent=%u state=%u",
                    568:                                host?host:"", user?user:"", db?db:"", port, mysql_flags,
                    569:                                conn? conn->persistent:0, conn? CONN_GET_STATE(conn):-1);
                    570: 
                    571:        if (conn && CONN_GET_STATE(conn) > CONN_ALLOCED && CONN_GET_STATE(conn) ) {
                    572:                DBG_INF("Connecting on a connected handle.");
                    573: 
                    574:                if (CONN_GET_STATE(conn) < CONN_QUIT_SENT) {
                    575:                        MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CLOSE_IMPLICIT);
                    576:                        reconnect = TRUE;
                    577:                        conn->m->send_close(conn TSRMLS_CC);
                    578:                }
                    579: 
                    580:                conn->m->free_contents(conn TSRMLS_CC);
                    581:                MYSQLND_DEC_CONN_STATISTIC(conn->stats, STAT_OPENED_CONNECTIONS);
                    582:                if (conn->persistent) {
                    583:                        MYSQLND_DEC_CONN_STATISTIC(conn->stats, STAT_OPENED_PERSISTENT_CONNECTIONS);
                    584:                }
                    585:                /* Now reconnect using the same handle */
                    586:                if (conn->net->compressed) {
                    587:                        /*
                    588:                          we need to save the state. As we will re-connect, net->compressed should be off, or
                    589:                          we will look for a compression header as part of the greet message, but there will
                    590:                          be none.
                    591:                        */
                    592:                        saved_compression = TRUE;
                    593:                        conn->net->compressed = FALSE;
                    594:                }
                    595:        }
                    596: 
                    597:        if (!host || !host[0]) {
                    598:                host = "localhost";
                    599:        }
                    600:        if (!user) {
                    601:                DBG_INF_FMT("no user given, using empty string");
                    602:                user = "";
                    603:        }
                    604:        if (!passwd) {
                    605:                DBG_INF_FMT("no password given, using empty string");
                    606:                passwd = "";
                    607:                passwd_len = 0;
                    608:        }
                    609:        if (!db) {
                    610:                DBG_INF_FMT("no db given, using empty string");
                    611:                db = "";
                    612:                db_len = 0;
                    613:        }
                    614: 
                    615:        host_len = strlen(host);
                    616:        {
                    617:                char * transport = NULL;
                    618:                int transport_len;
                    619: #ifndef PHP_WIN32
                    620:                if (host_len == sizeof("localhost") - 1 && !strncasecmp(host, "localhost", host_len)) {
                    621:                        DBG_INF_FMT("socket=%s", socket_or_pipe? socket_or_pipe:"n/a");
                    622:                        if (!socket_or_pipe) {
                    623:                                socket_or_pipe = "/tmp/mysql.sock";
                    624:                        }
                    625:                        transport_len = spprintf(&transport, 0, "unix://%s", socket_or_pipe);
                    626:                        unix_socket = TRUE;
                    627:                } else
                    628: #endif
                    629:                {
                    630:                        if (!port) {
                    631:                                port = 3306;
                    632:                        }
                    633:                        transport_len = spprintf(&transport, 0, "tcp://%s:%u", host, port);
                    634:                }
                    635:                if (!transport) {
                    636:                        SET_OOM_ERROR(conn->error_info);
                    637:                        goto err; /* OOM */
                    638:                }
                    639:                DBG_INF_FMT("transport=%s conn->scheme=%s", transport, conn->scheme);
                    640:                conn->scheme = mnd_pestrndup(transport, transport_len, conn->persistent);
                    641:                conn->scheme_len = transport_len;
                    642:                efree(transport); /* allocated by spprintf */
                    643:                transport = NULL;
                    644:                if (!conn->scheme) {
                    645:                        goto err; /* OOM */
                    646:                }
                    647:        }
                    648: 
                    649:        greet_packet = conn->protocol->m.get_greet_packet(conn->protocol, FALSE TSRMLS_CC);
                    650:        if (!greet_packet) {
                    651:                SET_OOM_ERROR(conn->error_info);
                    652:                goto err; /* OOM */
                    653:        }
                    654: 
                    655:        if (FAIL == conn->net->m.connect(conn->net, conn->scheme, conn->scheme_len, conn->persistent, &errstr, &errcode TSRMLS_CC)) {
                    656:                goto err;
                    657:        }
                    658: 
                    659:        DBG_INF_FMT("stream=%p", conn->net->stream);
                    660: 
                    661:        if (FAIL == PACKET_READ(greet_packet, conn)) {
                    662:                DBG_ERR("Error while reading greeting packet");
                    663:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading greeting packet. PID=%d", getpid());
                    664:                goto err;
                    665:        } else if (greet_packet->error_no) {
                    666:                DBG_ERR_FMT("errorno=%u error=%s", greet_packet->error_no, greet_packet->error);
                    667:                SET_CLIENT_ERROR(conn->error_info, greet_packet->error_no, greet_packet->sqlstate, greet_packet->error);
                    668:                goto err;
                    669:        } else if (greet_packet->pre41) {
                    670:                DBG_ERR_FMT("Connecting to 3.22, 3.23 & 4.0 is not supported. Server is %-.32s", greet_packet->server_version);
                    671:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connecting to 3.22, 3.23 & 4.0 "
                    672:                                                " is not supported. Server is %-.32s", greet_packet->server_version);
                    673:                SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE,
                    674:                                                 "Connecting to 3.22, 3.23 & 4.0 servers is not supported");
                    675:                goto err;
                    676:        }
                    677: 
                    678:        conn->thread_id                 = greet_packet->thread_id;
                    679:        conn->protocol_version  = greet_packet->protocol_version;
                    680:        conn->server_version    = mnd_pestrdup(greet_packet->server_version, conn->persistent);
                    681: 
                    682:        conn->greet_charset = mysqlnd_find_charset_nr(greet_packet->charset_no);
                    683:        /* we allow load data local infile by default */
                    684:        mysql_flags |= CLIENT_LOCAL_FILES | CLIENT_PS_MULTI_RESULTS;
                    685:        mysql_flags |= MYSQLND_CAPABILITIES;
                    686: 
                    687:        if (db) {
                    688:                mysql_flags |= CLIENT_CONNECT_WITH_DB;
                    689:        }
                    690: 
                    691:        if (PG(open_basedir) && strlen(PG(open_basedir))) {
                    692:                mysql_flags ^= CLIENT_LOCAL_FILES;
                    693:        }
                    694: 
                    695: #ifndef MYSQLND_COMPRESSION_ENABLED
                    696:        if (mysql_flags & CLIENT_COMPRESS) {
                    697:                mysql_flags &= ~CLIENT_COMPRESS;
                    698:        }
                    699: #else
                    700:        if (conn->net->options.flags & MYSQLND_NET_FLAG_USE_COMPRESSION) {
                    701:                mysql_flags |= CLIENT_COMPRESS;
                    702:        }
                    703: #endif
                    704: #ifndef MYSQLND_SSL_SUPPORTED
                    705:        if (mysql_flags & CLIENT_SSL) {
                    706:                mysql_flags &= ~CLIENT_SSL;
                    707:        }
                    708: #else
                    709:        if (conn->net->options.ssl_key || conn->net->options.ssl_cert ||
                    710:                conn->net->options.ssl_ca || conn->net->options.ssl_capath || conn->net->options.ssl_cipher)
                    711:        {
                    712:                mysql_flags |= CLIENT_SSL;
                    713:        }
                    714: #endif
                    715: 
                    716:        if (FAIL == mysqlnd_connect_run_authentication(conn, user, passwd, db, db_len, greet_packet, &conn->options, mysql_flags TSRMLS_CC)) {
                    717:                goto err;
                    718:        }
                    719: 
                    720:        {
                    721:                CONN_SET_STATE(conn, CONN_READY);
                    722: 
                    723:                if (saved_compression) {
                    724:                        conn->net->compressed = TRUE;
                    725:                }
                    726:                /*
                    727:                  If a connect on a existing handle is performed and mysql_flags is
                    728:                  passed which doesn't CLIENT_COMPRESS, then we need to overwrite the value
                    729:                  which we set based on saved_compression.
                    730:                */
                    731:                conn->net->compressed = mysql_flags & CLIENT_COMPRESS? TRUE:FALSE;
                    732: 
                    733:                conn->user                              = mnd_pestrdup(user, conn->persistent);
                    734:                conn->user_len                  = strlen(conn->user);
                    735:                conn->passwd                    = mnd_pestrndup(passwd, passwd_len, conn->persistent);
                    736:                conn->passwd_len                = passwd_len;
                    737:                conn->port                              = port;
                    738:                conn->connect_or_select_db = mnd_pestrndup(db, db_len, conn->persistent);
                    739:                conn->connect_or_select_db_len = db_len;
                    740: 
                    741:                if (!conn->user || !conn->passwd || !conn->connect_or_select_db) {
                    742:                        SET_OOM_ERROR(conn->error_info);
                    743:                        goto err; /* OOM */
                    744:                }
                    745: 
                    746:                if (!unix_socket) {
                    747:                        conn->host = mnd_pestrdup(host, conn->persistent);
                    748:                        if (!conn->host) {
                    749:                                SET_OOM_ERROR(conn->error_info);
                    750:                                goto err; /* OOM */
                    751:                        }
                    752:                        conn->host_len = strlen(conn->host);
                    753:                        {
                    754:                                char *p;
                    755:                                spprintf(&p, 0, "%s via TCP/IP", conn->host);
                    756:                                if (!p) {
                    757:                                        SET_OOM_ERROR(conn->error_info);
                    758:                                        goto err; /* OOM */
                    759:                                }
                    760:                                conn->host_info =  mnd_pestrdup(p, conn->persistent);
                    761:                                efree(p); /* allocated by spprintf */
                    762:                                if (!conn->host_info) {
                    763:                                        SET_OOM_ERROR(conn->error_info);
                    764:                                        goto err; /* OOM */
                    765:                                }
                    766:                        }
                    767:                } else {
                    768:                        conn->unix_socket       = mnd_pestrdup(socket_or_pipe, conn->persistent);
                    769:                        conn->host_info         = mnd_pestrdup("Localhost via UNIX socket", conn->persistent);
                    770:                        if (!conn->unix_socket || !conn->host_info) {
                    771:                                SET_OOM_ERROR(conn->error_info);
                    772:                                goto err; /* OOM */
                    773:                        }
                    774:                        conn->unix_socket_len = strlen(conn->unix_socket);
                    775:                }
                    776:                conn->client_flag               = mysql_flags;
                    777:                conn->max_packet_size   = MYSQLND_ASSEBLED_PACKET_MAX_SIZE;
                    778:                /* todo: check if charset is available */
                    779:                conn->server_capabilities = greet_packet->server_capabilities;
                    780:                conn->upsert_status.warning_count = 0;
                    781:                conn->upsert_status.server_status = greet_packet->server_status;
                    782:                conn->upsert_status.affected_rows = 0;
                    783: 
                    784:                SET_EMPTY_ERROR(conn->error_info);
                    785: 
                    786:                mysqlnd_local_infile_default(conn);
                    787: 
                    788: #if MYSQLND_UNICODE
                    789:                {
                    790:                        unsigned int as_unicode = 1;
                    791:                        conn->m->set_client_option(conn, MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE, (char *)&as_unicode TSRMLS_CC);
                    792:                        DBG_INF("unicode set");
                    793:                }
                    794: #endif
                    795:                if (conn->options.init_commands) {
                    796:                        unsigned int current_command = 0;
                    797:                        for (; current_command < conn->options.num_commands; ++current_command) {
                    798:                                const char * const command = conn->options.init_commands[current_command];
                    799:                                if (command) {
                    800:                                        MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_INIT_COMMAND_EXECUTED_COUNT);
                    801:                                        if (PASS != conn->m->query(conn, command, strlen(command) TSRMLS_CC)) {
                    802:                                                MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_INIT_COMMAND_FAILED_COUNT);
                    803:                                                goto err;
                    804:                                        }
                    805:                                        if (conn->last_query_type == QUERY_SELECT) {
                    806:                                                MYSQLND_RES * result = conn->m->use_result(conn TSRMLS_CC);
                    807:                                                if (result) {
                    808:                                                        result->m.free_result(result, TRUE TSRMLS_CC);
                    809:                                                }
                    810:                                        }
                    811:                                }
                    812:                        }
                    813:                }
                    814: 
                    815: 
                    816:                MYSQLND_INC_CONN_STATISTIC_W_VALUE2(conn->stats, STAT_CONNECT_SUCCESS, 1, STAT_OPENED_CONNECTIONS, 1);
                    817:                if (reconnect) {
                    818:                        MYSQLND_INC_GLOBAL_STATISTIC(STAT_RECONNECT);
                    819:                }
                    820:                if (conn->persistent) {
                    821:                        MYSQLND_INC_CONN_STATISTIC_W_VALUE2(conn->stats, STAT_PCONNECT_SUCCESS, 1, STAT_OPENED_PERSISTENT_CONNECTIONS, 1);
                    822:                }
                    823: 
                    824:                DBG_INF_FMT("connection_id=%llu", conn->thread_id);
                    825: 
                    826:                PACKET_FREE(greet_packet);
                    827: 
                    828:                DBG_RETURN(PASS);
                    829:        }
                    830: err:
                    831:        PACKET_FREE(greet_packet);
                    832: 
                    833:        if (errstr) {
                    834:                DBG_ERR_FMT("[%u] %.128s (trying to connect via %s)", errcode, errstr, conn->scheme);
                    835:                SET_CLIENT_ERROR(conn->error_info, errcode? errcode:CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, errstr);
                    836:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "[%u] %.128s (trying to connect via %s)", errcode, errstr, conn->scheme);
                    837:                /* no mnd_ since we don't allocate it */
                    838:                efree(errstr);
                    839:        }
                    840:        conn->m->free_contents(conn TSRMLS_CC);
                    841:        MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CONNECT_FAILURE);
                    842: 
                    843:        DBG_RETURN(FAIL);
                    844: }
                    845: /* }}} */
                    846: 
                    847: 
                    848: /* {{{ mysqlnd_connect */
                    849: PHPAPI MYSQLND * mysqlnd_connect(MYSQLND * conn,
                    850:                                                 const char *host, const char *user,
                    851:                                                 const char *passwd, unsigned int passwd_len,
                    852:                                                 const char *db, unsigned int db_len,
                    853:                                                 unsigned int port,
                    854:                                                 const char *socket_or_pipe,
                    855:                                                 unsigned int mysql_flags
                    856:                                                 TSRMLS_DC)
                    857: {
                    858:        enum_func_status ret = FAIL;
                    859:        zend_bool self_alloced = FALSE;
                    860: 
                    861:        DBG_ENTER("mysqlnd_connect");
                    862:        DBG_INF_FMT("host=%s user=%s db=%s port=%u flags=%u", host?host:"", user?user:"", db?db:"", port, mysql_flags);
                    863: 
                    864:        if (!conn) {
                    865:                self_alloced = TRUE;
                    866:                if (!(conn = mysqlnd_init(FALSE))) {
                    867:                        /* OOM */
                    868:                        DBG_RETURN(NULL);
                    869:                }
                    870:        }
                    871: 
                    872:        ret = conn->m->connect(conn, host, user, passwd, passwd_len, db, db_len, port, socket_or_pipe, mysql_flags TSRMLS_CC);
                    873: 
                    874:        if (ret == FAIL) {
                    875:                if (self_alloced) {
                    876:                        /*
                    877:                          We have alloced, thus there are no references to this
                    878:                          object - we are free to kill it!
                    879:                        */
                    880:                        conn->m->dtor(conn TSRMLS_CC);
                    881:                }
                    882:                DBG_RETURN(NULL);
                    883:        }
                    884:        DBG_RETURN(conn);
                    885: }
                    886: /* }}} */
                    887: 
                    888: 
                    889: /* {{{ mysqlnd_conn::change_user */
                    890: static enum_func_status
                    891: MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn,
                    892:                                                                                  const char *user,
                    893:                                                                                  const char *passwd,
                    894:                                                                                  const char *db,
                    895:                                                                                  zend_bool silent TSRMLS_DC)
                    896: {
                    897:        size_t user_len;
                    898:        enum_func_status ret = FAIL;
                    899:        MYSQLND_PACKET_CHG_USER_RESPONSE * chg_user_resp;
                    900:        char buffer[MYSQLND_MAX_ALLOWED_USER_LEN + 1 + 1 + SCRAMBLE_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1 + 2 /* charset*/ + 2];
                    901:        char *p = buffer;
                    902:        const MYSQLND_CHARSET * old_cs = conn->charset;
                    903: 
                    904:        DBG_ENTER("mysqlnd_conn::change_user");
                    905:        DBG_INF_FMT("conn=%llu user=%s passwd=%s db=%s silent=%u",
                    906:                                conn->thread_id, user?user:"", passwd?"***":"null", db?db:"", (silent == TRUE)?1:0 );
                    907: 
                    908:        SET_ERROR_AFF_ROWS(conn);
                    909: 
                    910:        if (!user) {
                    911:                user = "";
                    912:        }
                    913:        if (!passwd) {
                    914:                passwd = "";
                    915:        }
                    916:        if (!db) {
                    917:                db = "";
                    918:        }
                    919: 
                    920:        /* 1. user ASCIIZ */
                    921:        user_len = MIN(strlen(user), MYSQLND_MAX_ALLOWED_USER_LEN);
                    922:        memcpy(p, user, user_len);
                    923:        p += user_len;
                    924:        *p++ = '\0';
                    925: 
                    926:        /* 2. password SCRAMBLE_LENGTH followed by the scramble or \0 */
                    927:        if (passwd[0]) {
                    928:                *p++ = SCRAMBLE_LENGTH;
                    929:                php_mysqlnd_scramble((unsigned char *)p, conn->scramble, (unsigned char *)passwd);
                    930:                p += SCRAMBLE_LENGTH;
                    931:        } else {
                    932:                *p++ = '\0';
                    933:        }
                    934: 
                    935:        /* 3. db ASCIIZ */
                    936:        if (db[0]) {
                    937:                size_t db_len = MIN(strlen(db), MYSQLND_MAX_ALLOWED_DB_LEN);
                    938:                memcpy(p, db, db_len);
                    939:                p += db_len;
                    940:        }
                    941:        *p++ = '\0';
                    942: 
                    943:        /*
                    944:          4. request the current charset, or it will be reset to the system one.
                    945:          5.0 doesn't support it. Support added in 5.1.23 by fixing the following bug : 
                    946:          Bug #30472 libmysql doesn't reset charset, insert_id after succ. mysql_change_user() call
                    947:        */
                    948:        if (mysqlnd_get_server_version(conn) >= 50123) {
                    949:                int2store(p, conn->charset->nr);
                    950:                p+=2;
                    951:        }
                    952: 
                    953:        if (PASS != conn->m->simple_command(conn, COM_CHANGE_USER, buffer, p - buffer,
                    954:                                                                           PROT_LAST /* we will handle the OK packet*/,
                    955:                                                                           silent, TRUE TSRMLS_CC)) {
                    956:                DBG_RETURN(FAIL);
                    957:        }
                    958: 
                    959:        chg_user_resp = conn->protocol->m.get_change_user_response_packet(conn->protocol, FALSE TSRMLS_CC);
                    960:        if (!chg_user_resp) {
                    961:                SET_OOM_ERROR(conn->error_info);
                    962:                goto end;
                    963:        }
                    964:        ret = PACKET_READ(chg_user_resp, conn);
                    965:        conn->error_info = chg_user_resp->error_info;
                    966: 
                    967:        if (conn->error_info.error_no) {
                    968:                ret = FAIL;
                    969:                /*
                    970:                  COM_CHANGE_USER is broken in 5.1. At least in 5.1.15 and 5.1.14, 5.1.11 is immune.
                    971:                  bug#25371 mysql_change_user() triggers "packets out of sync"
                    972:                  When it gets fixed, there should be one more check here
                    973:                */
                    974:                if (mysqlnd_get_server_version(conn) > 50113L && mysqlnd_get_server_version(conn) < 50118L) {
                    975:                        MYSQLND_PACKET_OK * redundant_error_packet = conn->protocol->m.get_ok_packet(conn->protocol, FALSE TSRMLS_CC);
                    976:                        if (redundant_error_packet) {
                    977:                                PACKET_READ(redundant_error_packet, conn);
                    978:                                PACKET_FREE(redundant_error_packet);
                    979:                                DBG_INF_FMT("Server is %u, buggy, sends two ERR messages", mysqlnd_get_server_version(conn));
                    980:                        } else {
                    981:                                SET_OOM_ERROR(conn->error_info);
                    982:                        }
                    983:                }
                    984:        }
                    985:        if (ret == PASS) {
                    986:                char * tmp = NULL;
                    987:                /* if we get conn->user as parameter and then we first free it, then estrndup it, we will crash */
                    988:                tmp = mnd_pestrndup(user, user_len, conn->persistent);
                    989:                if (conn->user) {
                    990:                        mnd_pefree(conn->user, conn->persistent);
                    991:                }
                    992:                conn->user = tmp;
                    993: 
                    994:                tmp = mnd_pestrdup(passwd, conn->persistent);
                    995:                if (conn->passwd) {
                    996:                        mnd_pefree(conn->passwd, conn->persistent);
                    997:                }
                    998:                conn->passwd = tmp;
                    999: 
                   1000:                if (conn->last_message) {
                   1001:                        mnd_pefree(conn->last_message, conn->persistent);
                   1002:                        conn->last_message = NULL;
                   1003:                }
                   1004:                memset(&conn->upsert_status, 0, sizeof(conn->upsert_status));
                   1005:                /* set charset for old servers */
                   1006:                if (mysqlnd_get_server_version(conn) < 50123) {
                   1007:                        ret = conn->m->set_charset(conn, old_cs->name TSRMLS_CC);
                   1008:                }
                   1009:        } else if (ret == FAIL && chg_user_resp->server_asked_323_auth == TRUE) {
                   1010:                /* old authentication with new server  !*/
                   1011:                DBG_ERR(mysqlnd_old_passwd);
                   1012:                SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd);
                   1013:        }
                   1014: end:
                   1015:        PACKET_FREE(chg_user_resp);
                   1016: 
                   1017:        /*
                   1018:          Here we should close all statements. Unbuffered queries should not be a
                   1019:          problem as we won't allow sending COM_CHANGE_USER.
                   1020:        */
                   1021:        DBG_INF(ret == PASS? "PASS":"FAIL");
                   1022:        DBG_RETURN(ret);
                   1023: }
                   1024: /* }}} */
                   1025: 
                   1026: 
                   1027: /* {{{ mysqlnd_conn::query */
                   1028: /*
                   1029:   If conn->error_info.error_no is not zero, then we had an error.
                   1030:   Still the result from the query is PASS
                   1031: */
                   1032: static enum_func_status
                   1033: MYSQLND_METHOD(mysqlnd_conn, query)(MYSQLND * conn, const char * query, unsigned int query_len TSRMLS_DC)
                   1034: {
                   1035:        enum_func_status ret = FAIL;
                   1036:        DBG_ENTER("mysqlnd_conn::query");
                   1037:        DBG_INF_FMT("conn=%llu query=%s", conn->thread_id, query);
                   1038: 
                   1039:        if (PASS == conn->m->send_query(conn, query, query_len TSRMLS_CC) &&
                   1040:                PASS == conn->m->reap_query(conn TSRMLS_CC))
                   1041:        {
                   1042:                ret = PASS;
                   1043:                if (conn->last_query_type == QUERY_UPSERT && conn->upsert_status.affected_rows) {
                   1044:                        MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn->stats, STAT_ROWS_AFFECTED_NORMAL, conn->upsert_status.affected_rows);
                   1045:                }
                   1046:        }
                   1047:        DBG_RETURN(ret);
                   1048: }
                   1049: /* }}} */
                   1050: 
                   1051: 
                   1052: /* {{{ mysqlnd_conn::send_query */
                   1053: static enum_func_status
                   1054: MYSQLND_METHOD(mysqlnd_conn, send_query)(MYSQLND * conn, const char * query, unsigned int query_len TSRMLS_DC)
                   1055: {
                   1056:        enum_func_status ret;
                   1057:        DBG_ENTER("mysqlnd_conn::send_query");
                   1058:        DBG_INF_FMT("conn=%llu query=%s", conn->thread_id, query);
                   1059: 
                   1060:        ret = conn->m->simple_command(conn, COM_QUERY, query, query_len,
                   1061:                                                                 PROT_LAST /* we will handle the OK packet*/,
                   1062:                                                                 FALSE, FALSE TSRMLS_CC);
                   1063:        if (PASS == ret) {
                   1064:                CONN_SET_STATE(conn, CONN_QUERY_SENT);
                   1065:        }
                   1066:        DBG_RETURN(ret);
                   1067: }
                   1068: /* }}} */
                   1069: 
                   1070: 
                   1071: /* {{{ mysqlnd_conn::reap_query */
                   1072: static enum_func_status
                   1073: MYSQLND_METHOD(mysqlnd_conn, reap_query)(MYSQLND * conn TSRMLS_DC)
                   1074: {
                   1075:        enum_mysqlnd_connection_state state = CONN_GET_STATE(conn);
                   1076:        DBG_ENTER("mysqlnd_conn::reap_query");
                   1077:        DBG_INF_FMT("conn=%llu", conn->thread_id);
                   1078: 
                   1079:        if (state <= CONN_READY || state == CONN_QUIT_SENT) {
                   1080:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not opened, clear or has been closed");
                   1081:                DBG_ERR_FMT("Connection not opened, clear or has been closed. State=%u", state);
                   1082:                DBG_RETURN(FAIL);
                   1083:        }
                   1084:        /*
                   1085:          Here read the result set. We don't do it in simple_command because it need
                   1086:          information from the ok packet. We will fetch it ourselves.
                   1087:        */
                   1088:        DBG_RETURN(conn->m->query_read_result_set_header(conn, NULL TSRMLS_CC));
                   1089: }
                   1090: /* }}} */
                   1091: 
                   1092: 
                   1093: #include "php_network.h"
                   1094: 
                   1095: MYSQLND ** mysqlnd_stream_array_check_for_readiness(MYSQLND ** conn_array TSRMLS_DC)
                   1096: {
                   1097:        int cnt = 0;
                   1098:        MYSQLND **p = conn_array, **p_p;
                   1099:        MYSQLND **ret = NULL;
                   1100: 
                   1101:        while (*p) {
                   1102:                if (CONN_GET_STATE(*p) <= CONN_READY || CONN_GET_STATE(*p) == CONN_QUIT_SENT) {
                   1103:                        cnt++;
                   1104:                }
                   1105:                p++;
                   1106:        }
                   1107:        if (cnt) {
                   1108:                MYSQLND **ret_p = ret = ecalloc(cnt + 1, sizeof(MYSQLND *));
                   1109:                p_p = p = conn_array;
                   1110:                while (*p) {
                   1111:                        if (CONN_GET_STATE(*p) <= CONN_READY || CONN_GET_STATE(*p) == CONN_QUIT_SENT) {
                   1112:                                *ret_p = *p;
                   1113:                                *p = NULL;
                   1114:                                ret_p++;
                   1115:                        } else {
                   1116:                                *p_p = *p;
                   1117:                                p_p++;
                   1118:                        }
                   1119:                        p++;
                   1120:                }
                   1121:                *ret_p = NULL;
                   1122:        }
                   1123:        return ret;
                   1124: }
                   1125: 
                   1126: 
                   1127: /* {{{ stream_select mysqlnd_stream_array_to_fd_set functions */
                   1128: static int mysqlnd_stream_array_to_fd_set(MYSQLND **conn_array, fd_set *fds, php_socket_t *max_fd TSRMLS_DC)
                   1129: {
                   1130:        php_socket_t this_fd;
                   1131:        int cnt = 0;
                   1132:        MYSQLND **p = conn_array;
                   1133: 
                   1134:        while (*p) {
                   1135:                /* get the fd.
                   1136:                 * NB: Most other code will NOT use the PHP_STREAM_CAST_INTERNAL flag
                   1137:                 * when casting.  It is only used here so that the buffered data warning
                   1138:                 * is not displayed.
                   1139:                 * */
                   1140:                if (SUCCESS == php_stream_cast((*p)->net->stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL,
                   1141:                                                                                (void*)&this_fd, 1) && this_fd >= 0) {
                   1142: 
                   1143:                        PHP_SAFE_FD_SET(this_fd, fds);
                   1144: 
                   1145:                        if (this_fd > *max_fd) {
                   1146:                                *max_fd = this_fd;
                   1147:                        }
                   1148:                        cnt++;
                   1149:                }
                   1150:                p++;
                   1151:        }
                   1152:        return cnt ? 1 : 0;
                   1153: }
                   1154: 
                   1155: static int mysqlnd_stream_array_from_fd_set(MYSQLND **conn_array, fd_set *fds TSRMLS_DC)
                   1156: {
                   1157:        php_socket_t this_fd;
                   1158:        int ret = 0;
                   1159:        zend_bool disproportion = FALSE;
                   1160: 
                   1161: 
                   1162:        MYSQLND **fwd = conn_array, **bckwd = conn_array;
                   1163: 
                   1164:        while (*fwd) {
                   1165:                if (SUCCESS == php_stream_cast((*fwd)->net->stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL,
                   1166:                                                                                (void*)&this_fd, 1) && this_fd >= 0) {
                   1167:                        if (PHP_SAFE_FD_ISSET(this_fd, fds)) {
                   1168:                                if (disproportion) {
                   1169:                                        *bckwd = *fwd;
                   1170:                                }
                   1171:                                bckwd++;
                   1172:                                fwd++;
                   1173:                                ret++;
                   1174:                                continue;
                   1175:                        }
                   1176:                }
                   1177:                disproportion = TRUE;
                   1178:                fwd++;
                   1179:        }
                   1180:        *bckwd = NULL;/* NULL-terminate the list */
                   1181: 
                   1182:        return ret;
                   1183: }
                   1184: /* }}} */
                   1185: 
                   1186: #ifndef PHP_WIN32
                   1187: #define php_select(m, r, w, e, t)      select(m, r, w, e, t)
                   1188: #else
                   1189: #include "win32/select.h"
                   1190: #endif
                   1191: 
                   1192: /* {{{ _mysqlnd_poll */
                   1193: PHPAPI enum_func_status
                   1194: _mysqlnd_poll(MYSQLND **r_array, MYSQLND **e_array, MYSQLND ***dont_poll, long sec, long usec, uint * desc_num TSRMLS_DC)
                   1195: {
                   1196: 
                   1197:        struct timeval  tv;
                   1198:        struct timeval *tv_p = NULL;
                   1199:        fd_set                  rfds, wfds, efds;
                   1200:        php_socket_t    max_fd = 0;
                   1201:        int                             retval, sets = 0;
                   1202:        int                             set_count, max_set_count = 0;
                   1203:        DBG_ENTER("mysqlnd_poll");
                   1204: 
                   1205:        if (sec < 0 || usec < 0) {
                   1206:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Negative values passed for sec and/or usec");
                   1207:                DBG_RETURN(FAIL);
                   1208:        }
                   1209: 
                   1210:        *dont_poll = mysqlnd_stream_array_check_for_readiness(r_array TSRMLS_CC);
                   1211: 
                   1212:        FD_ZERO(&rfds);
                   1213:        FD_ZERO(&wfds);
                   1214:        FD_ZERO(&efds);
                   1215: 
                   1216:        if (r_array != NULL) {
                   1217:                set_count = mysqlnd_stream_array_to_fd_set(r_array, &rfds, &max_fd TSRMLS_CC);
                   1218:                if (set_count > max_set_count) {
                   1219:                        max_set_count = set_count;
                   1220:                }
                   1221:                sets += set_count;
                   1222:        }
                   1223: 
                   1224:        if (e_array != NULL) {
                   1225:                set_count = mysqlnd_stream_array_to_fd_set(e_array, &efds, &max_fd TSRMLS_CC);
                   1226:                if (set_count > max_set_count) {
                   1227:                        max_set_count = set_count;
                   1228:                }
                   1229:                sets += set_count;
                   1230:        }
                   1231: 
                   1232:        if (!sets) {
                   1233:                php_error_docref(NULL TSRMLS_CC, E_WARNING, *dont_poll ? "All arrays passed are clear":"No stream arrays were passed");
                   1234:                DBG_ERR_FMT(*dont_poll ? "All arrays passed are clear":"No stream arrays were passed");
                   1235:                DBG_RETURN(FAIL);
                   1236:        }
                   1237: 
                   1238:        PHP_SAFE_MAX_FD(max_fd, max_set_count);
                   1239: 
                   1240:        /* Solaris + BSD do not like microsecond values which are >= 1 sec */
                   1241:        if (usec > 999999) {
                   1242:                tv.tv_sec = sec + (usec / 1000000);
                   1243:                tv.tv_usec = usec % 1000000;
                   1244:        } else {
                   1245:                tv.tv_sec = sec;
                   1246:                tv.tv_usec = usec;
                   1247:        }
                   1248: 
                   1249:        tv_p = &tv;
                   1250: 
                   1251:        retval = php_select(max_fd + 1, &rfds, &wfds, &efds, tv_p);
                   1252: 
                   1253:        if (retval == -1) {
                   1254:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to select [%d]: %s (max_fd=%d)",
                   1255:                                                errno, strerror(errno), max_fd);
                   1256:                DBG_RETURN(FAIL);
                   1257:        }
                   1258: 
                   1259:        if (r_array != NULL) {
                   1260:                mysqlnd_stream_array_from_fd_set(r_array, &rfds TSRMLS_CC);
                   1261:        }
                   1262:        if (e_array != NULL) {
                   1263:                mysqlnd_stream_array_from_fd_set(e_array, &efds TSRMLS_CC);
                   1264:        }
                   1265: 
                   1266:        *desc_num = retval;
                   1267: 
                   1268:        DBG_RETURN(PASS);
                   1269: }
                   1270: /* }}} */
                   1271: 
                   1272: 
                   1273: /*
                   1274:   COM_FIELD_LIST is special, different from a SHOW FIELDS FROM :
                   1275:   - There is no result set header - status from the command, which
                   1276:     impacts us to allocate big chunk of memory for reading the metadata.
                   1277:   - The EOF packet is consumed by the metadata packet reader.
                   1278: */
                   1279: 
                   1280: /* {{{ mysqlnd_conn::list_fields */
                   1281: MYSQLND_RES *
                   1282: MYSQLND_METHOD(mysqlnd_conn, list_fields)(MYSQLND * conn, const char *table, const char *achtung_wild TSRMLS_DC)
                   1283: {
                   1284:        /* db + \0 + wild + \0 (for wild) */
                   1285:        char buff[MYSQLND_MAX_ALLOWED_DB_LEN * 2 + 1 + 1], *p;
                   1286:        size_t table_len, wild_len;
                   1287:        MYSQLND_RES *result = NULL;
                   1288:        DBG_ENTER("mysqlnd_conn::list_fields");
                   1289:        DBG_INF_FMT("conn=%llu table=%s wild=%s", conn->thread_id, table? table:"",achtung_wild? achtung_wild:"");
                   1290: 
                   1291:        p = buff;
                   1292:        if (table && (table_len = strlen(table))) {
                   1293:                size_t to_copy = MIN(table_len, MYSQLND_MAX_ALLOWED_DB_LEN);
                   1294:                memcpy(p, table, to_copy);
                   1295:                p += to_copy;
                   1296:                *p++ = '\0';
                   1297:        }
                   1298: 
                   1299:        if (achtung_wild && (wild_len = strlen(achtung_wild))) {
                   1300:                size_t to_copy = MIN(wild_len, MYSQLND_MAX_ALLOWED_DB_LEN);
                   1301:                memcpy(p, achtung_wild, to_copy);
                   1302:                p += to_copy;
                   1303:                *p++ = '\0';
                   1304:        }
                   1305: 
                   1306:        if (PASS != conn->m->simple_command(conn, COM_FIELD_LIST, buff, p - buff,
                   1307:                                                                           PROT_LAST /* we will handle the OK packet*/,
                   1308:                                                                           FALSE, TRUE TSRMLS_CC)) {
                   1309:                DBG_RETURN(NULL);
                   1310:        }
                   1311: 
                   1312:        /*
                   1313:           Prepare for the worst case.
                   1314:           MyISAM goes to 2500 BIT columns, double it for safety.
                   1315:        */
                   1316:        result = conn->m->result_init(5000, conn->persistent TSRMLS_CC);
                   1317:        if (!result) {
                   1318:                DBG_RETURN(NULL);
                   1319:        }
                   1320: 
                   1321:        if (FAIL == result->m.read_result_metadata(result, conn TSRMLS_CC)) {
                   1322:                DBG_ERR("Error ocurred while reading metadata");
                   1323:                result->m.free_result(result, TRUE TSRMLS_CC);
                   1324:                DBG_RETURN(NULL);
                   1325:        }
                   1326: 
                   1327:        result->type = MYSQLND_RES_NORMAL;
                   1328:        result->m.fetch_row = result->m.fetch_row_normal_unbuffered;
                   1329:        result->unbuf = mnd_ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
                   1330:        if (!result->unbuf) {
                   1331:                /* OOM */
                   1332:                SET_OOM_ERROR(conn->error_info);
                   1333:                result->m.free_result(result, TRUE TSRMLS_CC);
                   1334:                DBG_RETURN(NULL);
                   1335:        }
                   1336:        result->unbuf->eof_reached = TRUE;
                   1337: 
                   1338:        DBG_RETURN(result);
                   1339: }
                   1340: /* }}} */
                   1341: 
                   1342: 
                   1343: /* {{{ mysqlnd_conn::list_method */
                   1344: MYSQLND_RES *
                   1345: MYSQLND_METHOD(mysqlnd_conn, list_method)(MYSQLND * conn, const char * query, const char *achtung_wild, char *par1 TSRMLS_DC)
                   1346: {
                   1347:        char *show_query = NULL;
                   1348:        size_t show_query_len;
                   1349:        MYSQLND_RES *result = NULL;
                   1350: 
                   1351:        DBG_ENTER("mysqlnd_conn::list_method");
                   1352:        DBG_INF_FMT("conn=%llu query=%s wild=%u", conn->thread_id, query, achtung_wild);
                   1353: 
                   1354:        if (par1) {
                   1355:                if (achtung_wild) {
                   1356:                        show_query_len = spprintf(&show_query, 0, query, par1, achtung_wild);
                   1357:                } else {
                   1358:                        show_query_len = spprintf(&show_query, 0, query, par1);
                   1359:                }
                   1360:        } else {
                   1361:                if (achtung_wild) {
                   1362:                        show_query_len = spprintf(&show_query, 0, query, achtung_wild);
                   1363:                } else {
                   1364:                        show_query_len = strlen(show_query = (char *)query);
                   1365:                }
                   1366:        }
                   1367: 
                   1368:        if (PASS == conn->m->query(conn, show_query, show_query_len TSRMLS_CC)) {
                   1369:                result = conn->m->store_result(conn TSRMLS_CC);
                   1370:        }
                   1371:        if (show_query != query) {
                   1372:                efree(show_query); /* allocated by spprintf */
                   1373:        }
                   1374:        DBG_RETURN(result);
                   1375: }
                   1376: /* }}} */
                   1377: 
                   1378: 
                   1379: /* {{{ mysqlnd_conn::errno */
                   1380: static unsigned int
                   1381: MYSQLND_METHOD(mysqlnd_conn, errno)(const MYSQLND * const conn TSRMLS_DC)
                   1382: {
                   1383:        return conn->error_info.error_no;
                   1384: }
                   1385: /* }}} */
                   1386: 
                   1387: 
                   1388: /* {{{ mysqlnd_conn::error */
                   1389: static const char *
                   1390: MYSQLND_METHOD(mysqlnd_conn, error)(const MYSQLND * const conn TSRMLS_DC)
                   1391: {
                   1392:        return conn->error_info.error;
                   1393: }
                   1394: /* }}} */
                   1395: 
                   1396: 
                   1397: /* {{{ mysqlnd_conn::sqlstate */
                   1398: static const char *
                   1399: MYSQLND_METHOD(mysqlnd_conn, sqlstate)(const MYSQLND * const conn TSRMLS_DC)
                   1400: {
                   1401:        return conn->error_info.sqlstate[0] ? conn->error_info.sqlstate:MYSQLND_SQLSTATE_NULL;
                   1402: }
                   1403: /* }}} */
                   1404: 
                   1405: 
                   1406: /* {{{ mysqlnd_old_escape_string */
                   1407: PHPAPI ulong mysqlnd_old_escape_string(char *newstr, const char *escapestr, size_t escapestr_len TSRMLS_DC)
                   1408: {
                   1409:        DBG_ENTER("mysqlnd_old_escape_string");
                   1410:        DBG_RETURN(mysqlnd_cset_escape_slashes(mysqlnd_find_charset_name("latin1"), newstr, escapestr, escapestr_len TSRMLS_CC));
                   1411: }
                   1412: /* }}} */
                   1413: 
                   1414: /* {{{ mysqlnd_conn::ssl_set */
                   1415: static enum_func_status
                   1416: MYSQLND_METHOD(mysqlnd_conn, ssl_set)(MYSQLND * const conn, const char * key, const char * const cert, const char * const ca, const char * const capath, const char * const cipher TSRMLS_DC)
                   1417: {
                   1418:        return (PASS == conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_KEY, key TSRMLS_CC) &&
                   1419:                PASS == conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CERT, cert TSRMLS_CC) &&
                   1420:                PASS == conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CA, ca TSRMLS_CC) &&
                   1421:                PASS == conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CAPATH, capath TSRMLS_CC) &&
                   1422:                PASS == conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CIPHER, cipher TSRMLS_CC)) ? PASS : FAIL;
                   1423: }
                   1424: /* }}} */
                   1425: 
                   1426: 
                   1427: /* {{{ mysqlnd_conn::escape_string */
                   1428: static ulong
                   1429: MYSQLND_METHOD(mysqlnd_conn, escape_string)(MYSQLND * const conn, char *newstr, const char *escapestr, size_t escapestr_len TSRMLS_DC)
                   1430: {
                   1431:        DBG_ENTER("mysqlnd_conn::escape_string");
                   1432:        DBG_INF_FMT("conn=%llu", conn->thread_id);
                   1433:        if (conn->upsert_status.server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES) {
                   1434:                DBG_RETURN(mysqlnd_cset_escape_quotes(conn->charset, newstr, escapestr, escapestr_len TSRMLS_CC));
                   1435:        }
                   1436:        DBG_RETURN(mysqlnd_cset_escape_slashes(conn->charset, newstr, escapestr, escapestr_len TSRMLS_CC));
                   1437: }
                   1438: /* }}} */
                   1439: 
                   1440: 
                   1441: /* {{{ mysqlnd_conn::dump_debug_info */
                   1442: static enum_func_status
                   1443: MYSQLND_METHOD(mysqlnd_conn, dump_debug_info)(MYSQLND * const conn TSRMLS_DC)
                   1444: {
                   1445:        DBG_ENTER("mysqlnd_conn::dump_debug_info");
                   1446:        DBG_INF_FMT("conn=%llu", conn->thread_id);
                   1447:        DBG_RETURN(conn->m->simple_command(conn, COM_DEBUG, NULL, 0, PROT_EOF_PACKET, FALSE, TRUE TSRMLS_CC));
                   1448: }
                   1449: /* }}} */
                   1450: 
                   1451: 
                   1452: /* {{{ mysqlnd_conn::select_db */
                   1453: static enum_func_status
                   1454: MYSQLND_METHOD(mysqlnd_conn, select_db)(MYSQLND * const conn, const char * const db, unsigned int db_len TSRMLS_DC)
                   1455: {
                   1456:        enum_func_status ret;
                   1457: 
                   1458:        DBG_ENTER("mysqlnd_conn::select_db");
                   1459:        DBG_INF_FMT("conn=%llu db=%s", conn->thread_id, db);
                   1460: 
                   1461:        ret = conn->m->simple_command(conn, COM_INIT_DB, db, db_len, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC);
                   1462:        /*
                   1463:          The server sends 0 but libmysql doesn't read it and has established
                   1464:          a protocol of giving back -1. Thus we have to follow it :(
                   1465:        */
                   1466:        SET_ERROR_AFF_ROWS(conn);
                   1467:        if (ret == PASS) {
                   1468:                if (conn->connect_or_select_db) {
                   1469:                        mnd_pefree(conn->connect_or_select_db, conn->persistent);
                   1470:                }
                   1471:                conn->connect_or_select_db = mnd_pestrndup(db, db_len, conn->persistent);
                   1472:                conn->connect_or_select_db_len = db_len;
                   1473:                if (!conn->connect_or_select_db) {
                   1474:                        /* OOM */
                   1475:                        SET_OOM_ERROR(conn->error_info);
                   1476:                        ret = FAIL;
                   1477:                }
                   1478:        }
                   1479:        DBG_RETURN(ret);
                   1480: }
                   1481: /* }}} */
                   1482: 
                   1483: 
                   1484: /* {{{ mysqlnd_conn::ping */
                   1485: static enum_func_status
                   1486: MYSQLND_METHOD(mysqlnd_conn, ping)(MYSQLND * const conn TSRMLS_DC)
                   1487: {
                   1488:        enum_func_status ret;
                   1489: 
                   1490:        DBG_ENTER("mysqlnd_conn::ping");
                   1491:        DBG_INF_FMT("conn=%llu", conn->thread_id);
                   1492: 
                   1493:        ret = conn->m->simple_command(conn, COM_PING, NULL, 0, PROT_OK_PACKET, TRUE, TRUE TSRMLS_CC);
                   1494:        /*
                   1495:          The server sends 0 but libmysql doesn't read it and has established
                   1496:          a protocol of giving back -1. Thus we have to follow it :(
                   1497:        */
                   1498:        SET_ERROR_AFF_ROWS(conn);
                   1499: 
                   1500:        DBG_INF_FMT("ret=%u", ret);
                   1501:        DBG_RETURN(ret);
                   1502: }
                   1503: /* }}} */
                   1504: 
                   1505: 
                   1506: /* {{{ mysqlnd_conn::statistic */
                   1507: static enum_func_status
                   1508: MYSQLND_METHOD(mysqlnd_conn, statistic)(MYSQLND * conn, char **message, unsigned int * message_len TSRMLS_DC)
                   1509: {
                   1510:        enum_func_status ret;
                   1511:        MYSQLND_PACKET_STATS * stats_header;
                   1512: 
                   1513:        DBG_ENTER("mysqlnd_conn::statistic");
                   1514:        DBG_INF_FMT("conn=%llu", conn->thread_id);
                   1515: 
                   1516:        ret = conn->m->simple_command(conn, COM_STATISTICS, NULL, 0, PROT_LAST, FALSE, TRUE TSRMLS_CC);
                   1517:        if (FAIL == ret) {
                   1518:                DBG_RETURN(FAIL);
                   1519:        }
                   1520:        stats_header = conn->protocol->m.get_stats_packet(conn->protocol, FALSE TSRMLS_CC);
                   1521:        if (!stats_header) {
                   1522:                SET_OOM_ERROR(conn->error_info);
                   1523:                DBG_RETURN(FAIL);
                   1524:        }
                   1525: 
                   1526:        if (FAIL == (ret = PACKET_READ(stats_header, conn))) {
                   1527:                DBG_RETURN(FAIL);
                   1528:        }
                   1529:        /* will be freed by Zend, thus don't use the mnd_ allocator */
                   1530:        *message = estrndup(stats_header->message, stats_header->message_len); 
                   1531:        *message_len = stats_header->message_len;
                   1532:        PACKET_FREE(stats_header);
                   1533: 
                   1534:        DBG_INF(*message);
                   1535:        DBG_RETURN(PASS);
                   1536: }
                   1537: /* }}} */
                   1538: 
                   1539: 
                   1540: /* {{{ mysqlnd_conn::kill */
                   1541: static enum_func_status
                   1542: MYSQLND_METHOD(mysqlnd_conn, kill)(MYSQLND * conn, unsigned int pid TSRMLS_DC)
                   1543: {
                   1544:        enum_func_status ret;
                   1545:        char buff[4];
                   1546: 
                   1547:        DBG_ENTER("mysqlnd_conn::kill");
                   1548:        DBG_INF_FMT("conn=%llu pid=%u", conn->thread_id, pid);
                   1549: 
                   1550:        int4store(buff, pid);
                   1551: 
                   1552:        /* If we kill ourselves don't expect OK packet, PROT_LAST will skip it */
                   1553:        if (pid != conn->thread_id) {
                   1554:                ret = conn->m->simple_command(conn, COM_PROCESS_KILL, buff, 4, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC);
                   1555:                /*
                   1556:                  The server sends 0 but libmysql doesn't read it and has established
                   1557:                  a protocol of giving back -1. Thus we have to follow it :(
                   1558:                */
                   1559:                SET_ERROR_AFF_ROWS(conn);
                   1560:        } else if (PASS == (ret = conn->m->simple_command(conn, COM_PROCESS_KILL, buff, 4, PROT_LAST, FALSE, TRUE TSRMLS_CC))) {
                   1561:                CONN_SET_STATE(conn, CONN_QUIT_SENT);
                   1562:        }
                   1563:        DBG_RETURN(ret);
                   1564: }
                   1565: /* }}} */
                   1566: 
                   1567: 
                   1568: /* {{{ mysqlnd_conn::set_charset */
                   1569: static enum_func_status
                   1570: MYSQLND_METHOD(mysqlnd_conn, set_charset)(MYSQLND * const conn, const char * const csname TSRMLS_DC)
                   1571: {
                   1572:        enum_func_status ret = PASS;
                   1573:        char * query;
                   1574:        size_t query_len;
                   1575:        const MYSQLND_CHARSET * const charset = mysqlnd_find_charset_name(csname);
                   1576: 
                   1577:        DBG_ENTER("mysqlnd_conn::set_charset");
                   1578:        DBG_INF_FMT("conn=%llu cs=%s", conn->thread_id, csname);
                   1579: 
                   1580:        if (!charset) {
                   1581:                SET_CLIENT_ERROR(conn->error_info, CR_CANT_FIND_CHARSET, UNKNOWN_SQLSTATE,
                   1582:                                                 "Invalid characterset or character set not supported");
                   1583:                DBG_RETURN(FAIL);
                   1584:        }
                   1585: 
                   1586:        query_len = spprintf(&query, 0, "SET NAMES %s", csname);
                   1587: 
                   1588:        if (FAIL == conn->m->query(conn, query, query_len TSRMLS_CC)) {
                   1589:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error executing query");
                   1590:        } else if (conn->error_info.error_no) {
                   1591:                ret = FAIL;
                   1592:        } else {
                   1593:                conn->charset = charset;
                   1594:        }
                   1595:        efree(query); /* allocated by spprintf */
                   1596: 
                   1597:        DBG_INF(ret == PASS? "PASS":"FAIL");
                   1598:        DBG_RETURN(ret);
                   1599: }
                   1600: /* }}} */
                   1601: 
                   1602: 
                   1603: /* {{{ mysqlnd_conn::refresh */
                   1604: static enum_func_status
                   1605: MYSQLND_METHOD(mysqlnd_conn, refresh)(MYSQLND * const conn, uint8_t options TSRMLS_DC)
                   1606: {
                   1607:        zend_uchar bits[1];
                   1608:        DBG_ENTER("mysqlnd_conn::refresh");
                   1609:        DBG_INF_FMT("conn=%llu options=%lu", conn->thread_id, options);
                   1610: 
                   1611:        int1store(bits, options);
                   1612: 
                   1613:        DBG_RETURN(conn->m->simple_command(conn, COM_REFRESH, (char *)bits, 1, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC));
                   1614: }
                   1615: /* }}} */
                   1616: 
                   1617: 
                   1618: /* {{{ mysqlnd_conn::shutdown */
                   1619: static enum_func_status
                   1620: MYSQLND_METHOD(mysqlnd_conn, shutdown)(MYSQLND * const conn, uint8_t level TSRMLS_DC)
                   1621: {
                   1622:        zend_uchar bits[1];
                   1623:        DBG_ENTER("mysqlnd_conn::shutdown");
                   1624:        DBG_INF_FMT("conn=%llu level=%lu", conn->thread_id, level);
                   1625: 
                   1626:        int1store(bits, level);
                   1627: 
                   1628:        DBG_RETURN(conn->m->simple_command(conn, COM_SHUTDOWN, (char *)bits, 1, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC));
                   1629: }
                   1630: /* }}} */
                   1631: 
                   1632: 
                   1633: /* {{{ mysqlnd_send_close */
                   1634: static enum_func_status
                   1635: MYSQLND_METHOD(mysqlnd_conn, send_close)(MYSQLND * const conn TSRMLS_DC)
                   1636: {
                   1637:        enum_func_status ret = PASS;
                   1638: 
                   1639:        DBG_ENTER("mysqlnd_send_close");
                   1640:        DBG_INF_FMT("conn=%llu conn->net->stream->abstract=%p",
                   1641:                                conn->thread_id, conn->net->stream? conn->net->stream->abstract:NULL);
                   1642: 
                   1643:        switch (CONN_GET_STATE(conn)) {
                   1644:                case CONN_READY:
                   1645:                        DBG_INF("Connection clean, sending COM_QUIT");
                   1646:                        if (conn->net->stream) {
                   1647:                                ret =  conn->m->simple_command(conn, COM_QUIT, NULL, 0, PROT_LAST, TRUE, TRUE TSRMLS_CC);
                   1648:                        }
                   1649:                        /* Do nothing */
                   1650:                        break;
                   1651:                case CONN_SENDING_LOAD_DATA:
                   1652:                        /*
                   1653:                          Don't send COM_QUIT if we are in a middle of a LOAD DATA or we
                   1654:                          will crash (assert) a debug server.
                   1655:                        */
                   1656:                case CONN_NEXT_RESULT_PENDING:
                   1657:                case CONN_QUERY_SENT:
                   1658:                case CONN_FETCHING_DATA:
                   1659:                        MYSQLND_INC_GLOBAL_STATISTIC(STAT_CLOSE_IN_MIDDLE);
                   1660:                        DBG_ERR_FMT("Brutally closing connection [%p][%s]", conn, conn->scheme);
                   1661:                        /*
                   1662:                          Do nothing, the connection will be brutally closed
                   1663:                          and the server will catch it and free close from its side.
                   1664:                        */
                   1665:                case CONN_ALLOCED:
                   1666:                        /*
                   1667:                          Allocated but not connected or there was failure when trying
                   1668:                          to connect with pre-allocated connect.
                   1669: 
                   1670:                          Fall-through
                   1671:                        */
                   1672:                case CONN_QUIT_SENT:
                   1673:                        /* The user has killed its own connection */
                   1674:                        break;
                   1675:        }
                   1676:        /*
                   1677:          We hold one reference, and every other object which needs the
                   1678:          connection does increase it by 1.
                   1679:        */
                   1680:        CONN_SET_STATE(conn, CONN_QUIT_SENT);
                   1681: 
                   1682:        DBG_RETURN(ret);
                   1683: }
                   1684: /* }}} */
                   1685: 
                   1686: 
                   1687: /* {{{ mysqlnd_conn::close */
                   1688: static enum_func_status
                   1689: MYSQLND_METHOD(mysqlnd_conn, close)(MYSQLND * conn, enum_connection_close_type close_type TSRMLS_DC)
                   1690: {
                   1691:        enum_func_status ret = PASS;
                   1692:        static enum_mysqlnd_collected_stats
                   1693:        close_type_to_stat_map[MYSQLND_CLOSE_LAST] = {
                   1694:                STAT_CLOSE_EXPLICIT,
                   1695:                STAT_CLOSE_IMPLICIT,
                   1696:                STAT_CLOSE_DISCONNECT
                   1697:        };
                   1698:        enum_mysqlnd_collected_stats statistic = close_type_to_stat_map[close_type];
                   1699: 
                   1700:        DBG_ENTER("mysqlnd_conn::close");
                   1701:        DBG_INF_FMT("conn=%llu", conn->thread_id);
                   1702: 
                   1703:        if (conn->state >= CONN_READY) {
                   1704:                MYSQLND_INC_CONN_STATISTIC(conn->stats, statistic);
                   1705:                MYSQLND_DEC_CONN_STATISTIC(conn->stats, STAT_OPENED_CONNECTIONS);
                   1706:                if (conn->persistent) {
                   1707:                        MYSQLND_DEC_CONN_STATISTIC(conn->stats, STAT_OPENED_PERSISTENT_CONNECTIONS);
                   1708:                }
                   1709:        }
                   1710: 
                   1711:        /*
                   1712:          Close now, free_reference will try,
                   1713:          if we are last, but that's not a problem.
                   1714:        */
                   1715:        ret = conn->m->send_close(conn TSRMLS_CC);
                   1716: 
                   1717:        ret = conn->m->free_reference(conn TSRMLS_CC);
                   1718: 
                   1719:        DBG_RETURN(ret);
                   1720: }
                   1721: /* }}} */
                   1722: 
                   1723: 
                   1724: /* {{{ mysqlnd_conn::get_reference */
                   1725: static MYSQLND *
                   1726: MYSQLND_METHOD_PRIVATE(mysqlnd_conn, get_reference)(MYSQLND * const conn TSRMLS_DC)
                   1727: {
                   1728:        DBG_ENTER("mysqlnd_conn::get_reference");
                   1729:        ++conn->refcount;
                   1730:        DBG_INF_FMT("conn=%llu new_refcount=%u", conn->thread_id, conn->refcount);
                   1731:        DBG_RETURN(conn);
                   1732: }
                   1733: /* }}} */
                   1734: 
                   1735: 
                   1736: /* {{{ mysqlnd_conn::free_reference */
                   1737: static enum_func_status
                   1738: MYSQLND_METHOD_PRIVATE(mysqlnd_conn, free_reference)(MYSQLND * const conn TSRMLS_DC)
                   1739: {
                   1740:        enum_func_status ret = PASS;
                   1741:        DBG_ENTER("mysqlnd_conn::free_reference");
                   1742:        DBG_INF_FMT("conn=%llu old_refcount=%u", conn->thread_id, conn->refcount);
                   1743:        if (!(--conn->refcount)) {
                   1744:                /*
                   1745:                  No multithreading issues as we don't share the connection :)
                   1746:                  This will free the object too, of course because references has
                   1747:                  reached zero.
                   1748:                */
                   1749:                ret = conn->m->send_close(conn TSRMLS_CC);
                   1750:                conn->m->dtor(conn TSRMLS_CC);
                   1751:        }
                   1752:        DBG_RETURN(ret);
                   1753: }
                   1754: /* }}} */
                   1755: 
                   1756: 
                   1757: /* {{{ mysqlnd_conn::get_state */
                   1758: static enum mysqlnd_connection_state
                   1759: MYSQLND_METHOD_PRIVATE(mysqlnd_conn, get_state)(MYSQLND * const conn TSRMLS_DC)
                   1760: {
                   1761:        DBG_ENTER("mysqlnd_conn::get_state");
                   1762:        DBG_RETURN(conn->state);
                   1763: }
                   1764: /* }}} */
                   1765: 
                   1766: 
                   1767: /* {{{ mysqlnd_conn::set_state */
                   1768: static void
                   1769: MYSQLND_METHOD_PRIVATE(mysqlnd_conn, set_state)(MYSQLND * const conn, enum mysqlnd_connection_state new_state TSRMLS_DC)
                   1770: {
                   1771:        DBG_ENTER("mysqlnd_conn::set_state");
                   1772:        DBG_INF_FMT("New state=%u", new_state);
                   1773:        conn->state = new_state;
                   1774:        DBG_VOID_RETURN;
                   1775: }
                   1776: /* }}} */
                   1777: 
                   1778: 
                   1779: /* {{{ mysqlnd_conn::field_count */
                   1780: static unsigned int
                   1781: MYSQLND_METHOD(mysqlnd_conn, field_count)(const MYSQLND * const conn TSRMLS_DC)
                   1782: {
                   1783:        return conn->field_count;
                   1784: }
                   1785: /* }}} */
                   1786: 
                   1787: 
                   1788: /* {{{ mysqlnd_conn::insert_id */
                   1789: static uint64_t
                   1790: MYSQLND_METHOD(mysqlnd_conn, insert_id)(const MYSQLND * const conn TSRMLS_DC)
                   1791: {
                   1792:        return conn->upsert_status.last_insert_id;
                   1793: }
                   1794: /* }}} */
                   1795: 
                   1796: 
                   1797: /* {{{ mysqlnd_conn::affected_rows */
                   1798: static uint64_t
                   1799: MYSQLND_METHOD(mysqlnd_conn, affected_rows)(const MYSQLND * const conn TSRMLS_DC)
                   1800: {
                   1801:        return conn->upsert_status.affected_rows;
                   1802: }
                   1803: /* }}} */
                   1804: 
                   1805: 
                   1806: /* {{{ mysqlnd_conn::warning_count */
                   1807: static unsigned int
                   1808: MYSQLND_METHOD(mysqlnd_conn, warning_count)(const MYSQLND * const conn TSRMLS_DC)
                   1809: {
                   1810:        return conn->upsert_status.warning_count;
                   1811: }
                   1812: /* }}} */
                   1813: 
                   1814: 
                   1815: /* {{{ mysqlnd_conn::info */
                   1816: static const char *
                   1817: MYSQLND_METHOD(mysqlnd_conn, info)(const MYSQLND * const conn TSRMLS_DC)
                   1818: {
                   1819:        return conn->last_message;
                   1820: }
                   1821: /* }}} */
                   1822: 
                   1823: #if !defined(MYSQLND_USE_OPTIMISATIONS) || MYSQLND_USE_OPTIMISATIONS == 0
                   1824: /* {{{ mysqlnd_get_client_info */
                   1825: PHPAPI const char * mysqlnd_get_client_info()
                   1826: {
                   1827:        return MYSQLND_VERSION;
                   1828: }
                   1829: /* }}} */
                   1830: 
                   1831: 
                   1832: /* {{{ mysqlnd_get_client_version */
                   1833: PHPAPI unsigned int mysqlnd_get_client_version()
                   1834: {
                   1835:        return MYSQLND_VERSION_ID;
                   1836: }
                   1837: /* }}} */
                   1838: #endif
                   1839: 
                   1840: /* {{{ mysqlnd_conn::get_server_info */
                   1841: static const char *
                   1842: MYSQLND_METHOD(mysqlnd_conn, get_server_info)(const MYSQLND * const conn TSRMLS_DC)
                   1843: {
                   1844:        return conn->server_version;
                   1845: }
                   1846: /* }}} */
                   1847: 
                   1848: 
                   1849: /* {{{ mysqlnd_conn::get_host_info */
                   1850: static const char *
                   1851: MYSQLND_METHOD(mysqlnd_conn, get_host_info)(const MYSQLND * const conn TSRMLS_DC)
                   1852: {
                   1853:        return conn->host_info;
                   1854: }
                   1855: /* }}} */
                   1856: 
                   1857: 
                   1858: /* {{{ mysqlnd_conn::get_proto_info */
                   1859: static unsigned int
                   1860: MYSQLND_METHOD(mysqlnd_conn, get_proto_info)(const MYSQLND *const conn TSRMLS_DC)
                   1861: {
                   1862:        return conn->protocol_version;
                   1863: }
                   1864: /* }}} */
                   1865: 
                   1866: 
                   1867: /* {{{ mysqlnd_conn::charset_name */
                   1868: static const char *
                   1869: MYSQLND_METHOD(mysqlnd_conn, charset_name)(const MYSQLND * const conn TSRMLS_DC)
                   1870: {
                   1871:        return conn->charset->name;
                   1872: }
                   1873: /* }}} */
                   1874: 
                   1875: 
                   1876: /* {{{ mysqlnd_conn::thread_id */
                   1877: static uint64_t
                   1878: MYSQLND_METHOD(mysqlnd_conn, thread_id)(const MYSQLND * const conn TSRMLS_DC)
                   1879: {
                   1880:        return conn->thread_id;
                   1881: }
                   1882: /* }}} */
                   1883: 
                   1884: 
                   1885: /* {{{ mysqlnd_conn::get_server_version */
                   1886: static unsigned long
                   1887: MYSQLND_METHOD(mysqlnd_conn, get_server_version)(const MYSQLND * const conn TSRMLS_DC)
                   1888: {
                   1889:        long major, minor, patch;
                   1890:        char *p;
                   1891: 
                   1892:        if (!(p = conn->server_version)) {
                   1893:                return 0;
                   1894:        }
                   1895: 
                   1896:        major = strtol(p, &p, 10);
                   1897:        p += 1; /* consume the dot */
                   1898:        minor = strtol(p, &p, 10);
                   1899:        p += 1; /* consume the dot */
                   1900:        patch = strtol(p, &p, 10);
                   1901: 
                   1902:        return (unsigned long)(major * 10000L + (unsigned long)(minor * 100L + patch));
                   1903: }
                   1904: /* }}} */
                   1905: 
                   1906: 
                   1907: /* {{{ mysqlnd_conn::more_results */
                   1908: static zend_bool
                   1909: MYSQLND_METHOD(mysqlnd_conn, more_results)(const MYSQLND * const conn TSRMLS_DC)
                   1910: {
                   1911:        DBG_ENTER("mysqlnd_conn::more_results");
                   1912:        /* (conn->state == CONN_NEXT_RESULT_PENDING) too */
                   1913:        DBG_RETURN(conn->upsert_status.server_status & SERVER_MORE_RESULTS_EXISTS? TRUE:FALSE);
                   1914: }
                   1915: /* }}} */
                   1916: 
                   1917: 
                   1918: /* {{{ mysqlnd_conn::next_result */
                   1919: static enum_func_status
                   1920: MYSQLND_METHOD(mysqlnd_conn, next_result)(MYSQLND * const conn TSRMLS_DC)
                   1921: {
                   1922:        enum_func_status ret;
                   1923: 
                   1924:        DBG_ENTER("mysqlnd_conn::next_result");
                   1925:        DBG_INF_FMT("conn=%llu", conn->thread_id);
                   1926: 
                   1927:        if (CONN_GET_STATE(conn) != CONN_NEXT_RESULT_PENDING) {
                   1928:                DBG_RETURN(FAIL);
                   1929:        }
                   1930: 
                   1931:        SET_EMPTY_ERROR(conn->error_info);
                   1932:        SET_ERROR_AFF_ROWS(conn);
                   1933:        /*
                   1934:          We are sure that there is a result set, since conn->state is set accordingly
                   1935:          in mysqlnd_store_result() or mysqlnd_fetch_row_unbuffered()
                   1936:        */
                   1937:        if (FAIL == (ret = conn->m->query_read_result_set_header(conn, NULL TSRMLS_CC))) {
                   1938:                /*
                   1939:                  There can be an error in the middle of a multi-statement, which will cancel the multi-statement.
                   1940:                  So there are no more results and we should just return FALSE, error_no has been set
                   1941:                */
                   1942:                if (!conn->error_info.error_no) {
                   1943:                        DBG_ERR_FMT("Serious error. %s::%u", __FILE__, __LINE__);
                   1944:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Serious error. PID=%d", getpid());
                   1945:                        CONN_SET_STATE(conn, CONN_QUIT_SENT);
                   1946:                } else {
                   1947:                        DBG_INF_FMT("Error from the server : (%u) %s", conn->error_info.error_no, conn->error_info.error);
                   1948:                }
                   1949:        }
                   1950:        if (ret == PASS && conn->last_query_type == QUERY_UPSERT && conn->upsert_status.affected_rows) {
                   1951:                MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn->stats, STAT_ROWS_AFFECTED_NORMAL, conn->upsert_status.affected_rows);
                   1952:        }
                   1953: 
                   1954:        DBG_RETURN(ret);
                   1955: }
                   1956: /* }}} */
                   1957: 
                   1958: 
                   1959: /* {{{ mysqlnd_field_type_name */
                   1960: PHPAPI const char *mysqlnd_field_type_name(enum mysqlnd_field_types field_type)
                   1961: {
                   1962:        switch(field_type) {
                   1963:                case FIELD_TYPE_STRING:
                   1964:                case FIELD_TYPE_VAR_STRING:
                   1965:                        return "string";
                   1966:                case FIELD_TYPE_TINY:
                   1967:                case FIELD_TYPE_SHORT:
                   1968:                case FIELD_TYPE_LONG:
                   1969:                case FIELD_TYPE_LONGLONG:
                   1970:                case FIELD_TYPE_INT24:
                   1971:                        return "int";
                   1972:                case FIELD_TYPE_FLOAT:
                   1973:                case FIELD_TYPE_DOUBLE:
                   1974:                case FIELD_TYPE_DECIMAL:
                   1975:                case FIELD_TYPE_NEWDECIMAL:
                   1976:                        return "real";
                   1977:                case FIELD_TYPE_TIMESTAMP:
                   1978:                        return "timestamp";
                   1979:                case FIELD_TYPE_YEAR:
                   1980:                        return "year";
                   1981:                case FIELD_TYPE_DATE:
                   1982:                case FIELD_TYPE_NEWDATE:
                   1983:                        return "date";
                   1984:                case FIELD_TYPE_TIME:
                   1985:                        return "time";
                   1986:                case FIELD_TYPE_SET:
                   1987:                        return "set";
                   1988:                case FIELD_TYPE_ENUM:
                   1989:                        return "enum";
                   1990:                case FIELD_TYPE_GEOMETRY:
                   1991:                        return "geometry";
                   1992:                case FIELD_TYPE_DATETIME:
                   1993:                        return "datetime";
                   1994:                case FIELD_TYPE_TINY_BLOB:
                   1995:                case FIELD_TYPE_MEDIUM_BLOB:
                   1996:                case FIELD_TYPE_LONG_BLOB:
                   1997:                case FIELD_TYPE_BLOB:
                   1998:                        return "blob";
                   1999:                case FIELD_TYPE_NULL:
                   2000:                        return "null";
                   2001:                case FIELD_TYPE_BIT:
                   2002:                        return "bit";
                   2003:                default:
                   2004:                        return "unknown";
                   2005:        }
                   2006: }
                   2007: /* }}} */
                   2008: 
                   2009: 
                   2010: /* {{{ mysqlnd_conn::set_client_option */
                   2011: static enum_func_status
                   2012: MYSQLND_METHOD(mysqlnd_conn, set_client_option)(MYSQLND * const conn,
                   2013:                                                                                                enum mysqlnd_option option,
                   2014:                                                                                                const char * const value
                   2015:                                                                                                TSRMLS_DC)
                   2016: {
                   2017:        enum_func_status ret = PASS;
                   2018:        DBG_ENTER("mysqlnd_conn::set_client_option");
                   2019:        DBG_INF_FMT("conn=%llu option=%u", conn->thread_id, option);
                   2020:        switch (option) {
                   2021:                case MYSQL_OPT_COMPRESS:
                   2022: #ifdef WHEN_SUPPORTED_BY_MYSQLI
                   2023:                case MYSQL_OPT_READ_TIMEOUT:
                   2024:                case MYSQL_OPT_WRITE_TIMEOUT:
                   2025: #endif
                   2026:                case MYSQLND_OPT_SSL_KEY:
                   2027:                case MYSQLND_OPT_SSL_CERT:
                   2028:                case MYSQLND_OPT_SSL_CA:
                   2029:                case MYSQLND_OPT_SSL_CAPATH:
                   2030:                case MYSQLND_OPT_SSL_CIPHER:
                   2031:                case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
                   2032:                case MYSQL_OPT_CONNECT_TIMEOUT:
                   2033:                case MYSQLND_OPT_NET_CMD_BUFFER_SIZE:
                   2034:                case MYSQLND_OPT_NET_READ_BUFFER_SIZE:
                   2035:                        ret = conn->net->m.set_client_option(conn->net, option, value TSRMLS_CC);
                   2036:                        break;
                   2037: #if MYSQLND_UNICODE
                   2038:                case MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE:
                   2039:                        conn->options.numeric_and_datetime_as_unicode = *(unsigned int*) value;
                   2040:                        break;
                   2041: #endif
                   2042: #ifdef MYSQLND_STRING_TO_INT_CONVERSION
                   2043:                case MYSQLND_OPT_INT_AND_FLOAT_NATIVE:
                   2044:                        DBG_INF("MYSQLND_OPT_INT_AND_FLOAT_NATIVE");
                   2045:                        conn->options.int_and_float_native = *(unsigned int*) value;
                   2046:                        break;
                   2047: #endif
                   2048:                case MYSQL_OPT_LOCAL_INFILE:
                   2049:                        DBG_INF("MYSQL_OPT_LOCAL_INFILE");
                   2050:                        if (!value || (*(unsigned int*) value) ? 1 : 0) {
                   2051:                                conn->options.flags |= CLIENT_LOCAL_FILES;
                   2052:                        } else {
                   2053:                                conn->options.flags &= ~CLIENT_LOCAL_FILES;
                   2054:                        }
                   2055:                        break;
                   2056:                case MYSQL_INIT_COMMAND:
                   2057:                {
                   2058:                        char ** new_init_commands;
                   2059:                        char * new_command;
                   2060:                        DBG_INF("MYSQL_INIT_COMMAND");
                   2061:                        DBG_INF_FMT("command=%s", value);
                   2062:                        /* when num_commands is 0, then realloc will be effectively a malloc call, internally */
                   2063:                        /* Don't assign to conn->options.init_commands because in case of OOM we will lose the pointer and leak */
                   2064:                        new_init_commands = mnd_perealloc(conn->options.init_commands, sizeof(char *) * (conn->options.num_commands + 1), conn->persistent);
                   2065:                        if (!new_init_commands) {
                   2066:                                goto oom;
                   2067:                        }
                   2068:                        conn->options.init_commands = new_init_commands;
                   2069:                        new_command = mnd_pestrdup(value, conn->persistent);
                   2070:                        if (!new_command) {
                   2071:                                goto oom;
                   2072:                        }
                   2073:                        conn->options.init_commands[conn->options.num_commands] = new_command;
                   2074:                        ++conn->options.num_commands;
                   2075:                        break;
                   2076:                }
                   2077:                case MYSQL_READ_DEFAULT_FILE:
                   2078:                case MYSQL_READ_DEFAULT_GROUP:
                   2079: #ifdef WHEN_SUPPORTED_BY_MYSQLI
                   2080:                case MYSQL_SET_CLIENT_IP:
                   2081:                case MYSQL_REPORT_DATA_TRUNCATION:
                   2082: #endif
                   2083:                        /* currently not supported. Todo!! */
                   2084:                        break;
                   2085:                case MYSQL_SET_CHARSET_NAME:
                   2086:                {
                   2087:                        char * new_charset_name = mnd_pestrdup(value, conn->persistent);
                   2088:                        DBG_INF("MYSQL_SET_CHARSET_NAME");
                   2089:                        if (!new_charset_name) {
                   2090:                                goto oom;
                   2091:                        }
                   2092:                        if (conn->options.charset_name) {
                   2093:                                mnd_pefree(conn->options.charset_name, conn->persistent);
                   2094:                        }
                   2095:                        conn->options.charset_name = new_charset_name;
                   2096:                        DBG_INF_FMT("charset=%s", conn->options.charset_name);
                   2097:                        break;
                   2098:                }
                   2099:                case MYSQL_OPT_NAMED_PIPE:
                   2100:                        conn->options.protocol = MYSQL_PROTOCOL_PIPE;
                   2101:                        break;
                   2102:                case MYSQL_OPT_PROTOCOL:
                   2103:                        if (*(unsigned int*) value < MYSQL_PROTOCOL_LAST) {
                   2104:                                conn->options.protocol = *(unsigned int*) value;
                   2105:                        }
                   2106:                        break;
                   2107: #ifdef WHEN_SUPPORTED_BY_MYSQLI
                   2108:                case MYSQL_SET_CHARSET_DIR:
                   2109:                case MYSQL_OPT_RECONNECT:
                   2110:                        /* we don't need external character sets, all character sets are
                   2111:                           compiled in. For compatibility we just ignore this setting.
                   2112:                           Same for protocol, we don't support old protocol */
                   2113:                case MYSQL_OPT_USE_REMOTE_CONNECTION:
                   2114:                case MYSQL_OPT_USE_EMBEDDED_CONNECTION:
                   2115:                case MYSQL_OPT_GUESS_CONNECTION:
                   2116:                        /* todo: throw an error, we don't support embedded */
                   2117:                        break;
                   2118: #endif
                   2119: 
                   2120: #ifdef WHEN_SUPPORTED_BY_MYSQLI
                   2121:                case MYSQL_SHARED_MEMORY_BASE_NAME:
                   2122:                case MYSQL_OPT_USE_RESULT:
                   2123:                case MYSQL_SECURE_AUTH:
                   2124:                        /* not sure, todo ? */
                   2125: #endif
                   2126:                default:
                   2127:                        ret = FAIL;
                   2128:        }
                   2129:        DBG_RETURN(ret);
                   2130: oom:
                   2131:        SET_OOM_ERROR(conn->error_info);
                   2132:        DBG_RETURN(FAIL);
                   2133: }
                   2134: /* }}} */
                   2135: 
                   2136: 
                   2137: /* {{{ mysqlnd_conn::use_result */
                   2138: static MYSQLND_RES *
                   2139: MYSQLND_METHOD(mysqlnd_conn, use_result)(MYSQLND * const conn TSRMLS_DC)
                   2140: {
                   2141:        MYSQLND_RES * result;
                   2142: 
                   2143:        DBG_ENTER("mysqlnd_conn::use_result");
                   2144:        DBG_INF_FMT("conn=%llu", conn->thread_id);
                   2145: 
                   2146:        if (!conn->current_result) {
                   2147:                DBG_RETURN(NULL);
                   2148:        }
                   2149: 
                   2150:        /* Nothing to store for UPSERT/LOAD DATA */
                   2151:        if (conn->last_query_type != QUERY_SELECT || CONN_GET_STATE(conn) != CONN_FETCHING_DATA) {
                   2152:                SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
                   2153:                                                 mysqlnd_out_of_sync);
                   2154:                DBG_ERR("Command out of sync");
                   2155:                DBG_RETURN(NULL);
                   2156:        }
                   2157: 
                   2158:        MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_UNBUFFERED_SETS);
                   2159: 
                   2160:        conn->current_result->conn = conn->m->get_reference(conn TSRMLS_CC);
                   2161:        result = conn->current_result->m.use_result(conn->current_result, FALSE TSRMLS_CC);
                   2162: 
                   2163:        if (!result) {
                   2164:                conn->current_result->m.free_result(conn->current_result, TRUE TSRMLS_CC);
                   2165:        }
                   2166:        conn->current_result = NULL;
                   2167: 
                   2168:        DBG_RETURN(result);
                   2169: }
                   2170: /* }}} */
                   2171: 
                   2172: 
                   2173: /* {{{ mysqlnd_conn::store_result */
                   2174: static MYSQLND_RES *
                   2175: MYSQLND_METHOD(mysqlnd_conn, store_result)(MYSQLND * const conn TSRMLS_DC)
                   2176: {
                   2177:        MYSQLND_RES *result;
                   2178: 
                   2179:        DBG_ENTER("mysqlnd_conn::store_result");
                   2180:        DBG_INF_FMT("conn=%llu", conn->thread_id);
                   2181: 
                   2182:        if (!conn->current_result) {
                   2183:                DBG_RETURN(NULL);
                   2184:        }
                   2185: 
                   2186:        /* Nothing to store for UPSERT/LOAD DATA*/
                   2187:        if (conn->last_query_type != QUERY_SELECT || CONN_GET_STATE(conn) != CONN_FETCHING_DATA) {
                   2188:                SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
                   2189:                                                 mysqlnd_out_of_sync);
                   2190:                DBG_ERR("Command out of sync");
                   2191:                DBG_RETURN(NULL);
                   2192:        }
                   2193: 
                   2194:        MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_BUFFERED_SETS);
                   2195: 
                   2196:        result = conn->current_result->m.store_result(conn->current_result, conn, FALSE TSRMLS_CC);
                   2197:        if (!result) {
                   2198:                conn->current_result->m.free_result(conn->current_result, TRUE TSRMLS_CC);
                   2199:        }
                   2200:        conn->current_result = NULL;
                   2201:        DBG_RETURN(result);
                   2202: }
                   2203: /* }}} */
                   2204: 
                   2205: 
                   2206: /* {{{ mysqlnd_conn::get_connection_stats */
                   2207: static void
                   2208: MYSQLND_METHOD(mysqlnd_conn, get_connection_stats)(const MYSQLND * const conn,
                   2209:                                                                                                   zval *return_value
                   2210:                                                                                                   TSRMLS_DC ZEND_FILE_LINE_DC)
                   2211: {
                   2212:        DBG_ENTER("mysqlnd_conn::get_connection_stats");
                   2213:        DBG_INF_FMT("conn=%llu", conn->thread_id);
                   2214:        mysqlnd_fill_stats_hash(conn->stats, mysqlnd_stats_values_names, return_value TSRMLS_CC ZEND_FILE_LINE_CC);
                   2215:        DBG_VOID_RETURN;
                   2216: }
                   2217: /* }}} */
                   2218: 
                   2219: 
                   2220: /* {{{ mysqlnd_conn::set_autocommit */
                   2221: static enum_func_status
                   2222: MYSQLND_METHOD(mysqlnd_conn, set_autocommit)(MYSQLND * conn, unsigned int mode TSRMLS_DC)
                   2223: {
                   2224:        enum_func_status ret;
                   2225:        DBG_ENTER("mysqlnd_conn::set_autocommit");
                   2226:        ret = conn->m->query(conn, (mode) ? "SET AUTOCOMMIT=1":"SET AUTOCOMMIT=0", sizeof("SET AUTOCOMMIT=1") - 1 TSRMLS_CC);
                   2227:        DBG_RETURN(ret);
                   2228: }
                   2229: /* }}} */
                   2230: 
                   2231: 
                   2232: /* {{{ mysqlnd_conn::tx_commit */
                   2233: static enum_func_status
                   2234: MYSQLND_METHOD(mysqlnd_conn, tx_commit)(MYSQLND * conn TSRMLS_DC)
                   2235: {
                   2236:        enum_func_status ret;
                   2237:        DBG_ENTER("mysqlnd_conn::tx_commit");
                   2238:        ret = conn->m->query(conn, "COMMIT", sizeof("COMMIT") - 1 TSRMLS_CC);
                   2239:        DBG_RETURN(ret);
                   2240: }
                   2241: /* }}} */
                   2242: 
                   2243: 
                   2244: /* {{{ mysqlnd_conn::tx_rollback */
                   2245: static enum_func_status
                   2246: MYSQLND_METHOD(mysqlnd_conn, tx_rollback)(MYSQLND * conn TSRMLS_DC)
                   2247: {
                   2248:        enum_func_status ret;
                   2249:        DBG_ENTER("mysqlnd_conn::tx_rollback");
                   2250:        ret = conn->m->query(conn, "ROLLBACK", sizeof("ROLLBACK") - 1 TSRMLS_CC);
                   2251:        DBG_RETURN(ret);
                   2252: }
                   2253: /* }}} */
                   2254: 
                   2255: 
                   2256: 
                   2257: MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND * const conn TSRMLS_DC);
                   2258: static enum_func_status MYSQLND_METHOD(mysqlnd_conn, init)(MYSQLND * conn TSRMLS_DC);
                   2259: 
                   2260: static
                   2261: MYSQLND_CLASS_METHODS_START(mysqlnd_conn)
                   2262:        MYSQLND_METHOD(mysqlnd_conn, init),
                   2263:        MYSQLND_METHOD(mysqlnd_conn, connect),
                   2264: 
                   2265:        MYSQLND_METHOD(mysqlnd_conn, escape_string),
                   2266:        MYSQLND_METHOD(mysqlnd_conn, set_charset),
                   2267:        MYSQLND_METHOD(mysqlnd_conn, query),
                   2268:        MYSQLND_METHOD(mysqlnd_conn, send_query),
                   2269:        MYSQLND_METHOD(mysqlnd_conn, reap_query),
                   2270:        MYSQLND_METHOD(mysqlnd_conn, use_result),
                   2271:        MYSQLND_METHOD(mysqlnd_conn, store_result),
                   2272:        MYSQLND_METHOD(mysqlnd_conn, next_result),
                   2273:        MYSQLND_METHOD(mysqlnd_conn, more_results),
                   2274: 
                   2275:        _mysqlnd_stmt_init,
                   2276: 
                   2277:        MYSQLND_METHOD(mysqlnd_conn, shutdown),
                   2278:        MYSQLND_METHOD(mysqlnd_conn, refresh),
                   2279: 
                   2280:        MYSQLND_METHOD(mysqlnd_conn, ping),
                   2281:        MYSQLND_METHOD(mysqlnd_conn, kill),
                   2282:        MYSQLND_METHOD(mysqlnd_conn, select_db),
                   2283:        MYSQLND_METHOD(mysqlnd_conn, dump_debug_info),
                   2284:        MYSQLND_METHOD(mysqlnd_conn, change_user),
                   2285: 
                   2286:        MYSQLND_METHOD(mysqlnd_conn, errno),
                   2287:        MYSQLND_METHOD(mysqlnd_conn, error),
                   2288:        MYSQLND_METHOD(mysqlnd_conn, sqlstate),
                   2289:        MYSQLND_METHOD(mysqlnd_conn, thread_id),
                   2290: 
                   2291:        MYSQLND_METHOD(mysqlnd_conn, get_connection_stats),
                   2292: 
                   2293:        MYSQLND_METHOD(mysqlnd_conn, get_server_version),
                   2294:        MYSQLND_METHOD(mysqlnd_conn, get_server_info),
                   2295:        MYSQLND_METHOD(mysqlnd_conn, statistic),
                   2296:        MYSQLND_METHOD(mysqlnd_conn, get_host_info),
                   2297:        MYSQLND_METHOD(mysqlnd_conn, get_proto_info),
                   2298:        MYSQLND_METHOD(mysqlnd_conn, info),
                   2299:        MYSQLND_METHOD(mysqlnd_conn, charset_name),
                   2300:        MYSQLND_METHOD(mysqlnd_conn, list_fields),
                   2301:        MYSQLND_METHOD(mysqlnd_conn, list_method),
                   2302: 
                   2303:        MYSQLND_METHOD(mysqlnd_conn, insert_id),
                   2304:        MYSQLND_METHOD(mysqlnd_conn, affected_rows),
                   2305:        MYSQLND_METHOD(mysqlnd_conn, warning_count),
                   2306:        MYSQLND_METHOD(mysqlnd_conn, field_count),
                   2307: 
                   2308:        MYSQLND_METHOD(mysqlnd_conn, set_server_option),
                   2309:        MYSQLND_METHOD(mysqlnd_conn, set_client_option),
                   2310:        MYSQLND_METHOD(mysqlnd_conn, free_contents),
                   2311:        MYSQLND_METHOD(mysqlnd_conn, free_options),
                   2312:        MYSQLND_METHOD(mysqlnd_conn, close),
                   2313: 
                   2314:        MYSQLND_METHOD_PRIVATE(mysqlnd_conn, dtor),
                   2315: 
                   2316:        mysqlnd_query_read_result_set_header,
                   2317: 
                   2318:        MYSQLND_METHOD_PRIVATE(mysqlnd_conn, get_reference),
                   2319:        MYSQLND_METHOD_PRIVATE(mysqlnd_conn, free_reference),
                   2320:        MYSQLND_METHOD_PRIVATE(mysqlnd_conn, get_state),
                   2321:        MYSQLND_METHOD_PRIVATE(mysqlnd_conn, set_state),
                   2322: 
                   2323:        MYSQLND_METHOD(mysqlnd_conn, simple_command),
                   2324:        MYSQLND_METHOD(mysqlnd_conn, simple_command_handle_response),
                   2325:        MYSQLND_METHOD(mysqlnd_conn, restart_psession),
                   2326:        MYSQLND_METHOD(mysqlnd_conn, end_psession),
                   2327:        MYSQLND_METHOD(mysqlnd_conn, send_close),
                   2328: 
                   2329:        MYSQLND_METHOD(mysqlnd_conn, ssl_set),
                   2330:        mysqlnd_result_init
                   2331: #ifdef AUTOCOMMIT_TX_COMMIT_ROLLBACK
                   2332:        ,MYSQLND_METHOD(mysqlnd_conn, set_autocommit),
                   2333:        MYSQLND_METHOD(mysqlnd_conn, tx_commit),
                   2334:        MYSQLND_METHOD(mysqlnd_conn, tx_rollback)
                   2335: #endif
                   2336: MYSQLND_CLASS_METHODS_END;
                   2337: 
                   2338: 
                   2339: /* {{{ mysqlnd_conn::init */
                   2340: static enum_func_status
                   2341: MYSQLND_METHOD(mysqlnd_conn, init)(MYSQLND * conn TSRMLS_DC)
                   2342: {
                   2343:        DBG_ENTER("mysqlnd_conn::init");
                   2344:        mysqlnd_stats_init(&conn->stats, STAT_LAST);
                   2345:        SET_ERROR_AFF_ROWS(conn);
                   2346: 
                   2347:        conn->net = mysqlnd_net_init(conn->persistent TSRMLS_CC);
                   2348:        conn->protocol = mysqlnd_protocol_init(conn->persistent TSRMLS_CC);
                   2349: 
                   2350:        DBG_RETURN(conn->net && conn->protocol? PASS:FAIL);
                   2351: }
                   2352: /* }}} */
                   2353: 
                   2354: 
                   2355: /* {{{ mysqlnd_init */
                   2356: PHPAPI MYSQLND * _mysqlnd_init(zend_bool persistent TSRMLS_DC)
                   2357: {
                   2358:        size_t alloc_size = sizeof(MYSQLND) + mysqlnd_plugin_count() * sizeof(void *);
                   2359:        MYSQLND *ret;
                   2360: 
                   2361:        DBG_ENTER("mysqlnd_init");
                   2362:        DBG_INF_FMT("persistent=%u", persistent);
                   2363:        ret = mnd_pecalloc(1, alloc_size, persistent);
                   2364:        if (!ret) {
                   2365:                DBG_RETURN(NULL);
                   2366:        }
                   2367: 
                   2368:        ret->persistent = persistent;
                   2369:        ret->m = mysqlnd_conn_methods;
                   2370:        CONN_SET_STATE(ret, CONN_ALLOCED);
                   2371:        ret->m->get_reference(ret TSRMLS_CC);
                   2372: 
                   2373:        if (PASS != ret->m->init(ret TSRMLS_CC)) {
                   2374:                ret->m->dtor(ret TSRMLS_CC);
                   2375:                ret = NULL;
                   2376:        }
                   2377: 
                   2378:        DBG_RETURN(ret);
                   2379: }
                   2380: /* }}} */
                   2381: 
                   2382: 
                   2383: /* {{{ mysqlnd_library_init */
                   2384: PHPAPI void mysqlnd_library_init(TSRMLS_D)
                   2385: {
                   2386:        if (mysqlnd_library_initted == FALSE) {
                   2387:                mysqlnd_library_initted = TRUE;
                   2388:                mysqlnd_conn_methods = &MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_conn);
                   2389:                _mysqlnd_init_ps_subsystem();
                   2390:                /* Should be calloc, as mnd_calloc will reference LOCK_access*/
                   2391:                mysqlnd_stats_init(&mysqlnd_global_stats, STAT_LAST);
                   2392:        }
                   2393: }
                   2394: /* }}} */
                   2395: 
                   2396: /* {{{ mysqlnd_conn_get_methods */
                   2397: PHPAPI struct st_mysqlnd_conn_methods * mysqlnd_conn_get_methods()
                   2398: {
                   2399:        return mysqlnd_conn_methods;
                   2400: }
                   2401: /* }}} */
                   2402: 
                   2403: /* {{{ mysqlnd_conn_set_methods */
                   2404: PHPAPI void mysqlnd_conn_set_methods(struct st_mysqlnd_conn_methods *methods)
                   2405: {
                   2406:        mysqlnd_conn_methods = methods;
                   2407: }
                   2408: /* }}} */
                   2409: 
                   2410: 
                   2411: static unsigned int mysqlnd_plugins_counter = 0;
                   2412: 
                   2413: /* {{{ mysqlnd_plugin_register */
                   2414: PHPAPI unsigned int mysqlnd_plugin_register()
                   2415: {
                   2416:        return mysqlnd_plugins_counter++;
                   2417: }
                   2418: /* }}} */
                   2419: 
                   2420: 
                   2421: /* {{{ mysqlnd_plugin_count */
                   2422: PHPAPI unsigned int mysqlnd_plugin_count()
                   2423: {
                   2424:        return mysqlnd_plugins_counter;
                   2425: }
                   2426: /* }}} */
                   2427: 
                   2428: 
                   2429: /* {{{ _mysqlnd_plugin_get_plugin_connection_data */
                   2430: PHPAPI void ** _mysqlnd_plugin_get_plugin_connection_data(const MYSQLND * conn, unsigned int plugin_id TSRMLS_DC)
                   2431: {
                   2432:        DBG_ENTER("_mysqlnd_plugin_get_plugin_connection_data");
                   2433:        DBG_INF_FMT("plugin_id=%u", plugin_id);
                   2434:        if (!conn || plugin_id >= mysqlnd_plugin_count()) {
                   2435:                return NULL;
                   2436:        }
                   2437:        DBG_RETURN((void *)((char *)conn + sizeof(MYSQLND) + plugin_id * sizeof(void *)));
                   2438: }
                   2439: /* }}} */
                   2440: 
                   2441: /*
                   2442:  * Local variables:
                   2443:  * tab-width: 4
                   2444:  * c-basic-offset: 4
                   2445:  * End:
                   2446:  * vim600: noet sw=4 ts=4 fdm=marker
                   2447:  * vim<600: noet sw=4 ts=4
                   2448:  */

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