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

1.1     ! misho       1: /*
        !             2:   +----------------------------------------------------------------------+
        !             3:   | PHP Version 5                                                        |
        !             4:   +----------------------------------------------------------------------+
        !             5:   | Copyright (c) 2006-2012 The PHP Group                                |
        !             6:   +----------------------------------------------------------------------+
        !             7:   | This source file is subject to version 3.01 of the PHP license,      |
        !             8:   | that is bundled with this package in the file LICENSE, and is        |
        !             9:   | available through the world-wide-web at the following url:           |
        !            10:   | http://www.php.net/license/3_01.txt                                  |
        !            11:   | If you did not receive a copy of the PHP license and are unable to   |
        !            12:   | obtain it through the world-wide-web, please send a note to          |
        !            13:   | license@php.net so we can mail you a copy immediately.               |
        !            14:   +----------------------------------------------------------------------+
        !            15:   | Authors: Georg Richter <georg@mysql.com>                             |
        !            16:   |          Andrey Hristov <andrey@mysql.com>                           |
        !            17:   |          Ulf Wendel <uwendel@mysql.com>                              |
        !            18:   +----------------------------------------------------------------------+
        !            19: */
        !            20: 
        !            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>