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

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

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