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

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.1.4 ! misho    1064:        enum_func_status ret = FAIL;
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;
1.1.1.4 ! misho    1145:        php_stream *stream = NULL;
1.1       misho    1146:        int cnt = 0;
                   1147:        MYSQLND **p = conn_array;
                   1148: 
                   1149:        while (*p) {
                   1150:                /* get the fd.
                   1151:                 * NB: Most other code will NOT use the PHP_STREAM_CAST_INTERNAL flag
                   1152:                 * when casting.  It is only used here so that the buffered data warning
                   1153:                 * is not displayed.
                   1154:                 * */
1.1.1.4 ! misho    1155:                stream = (*p)->data->net->stream;
        !          1156:                if (stream != NULL && SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL,
1.1       misho    1157:                                                                                (void*)&this_fd, 1) && this_fd >= 0) {
                   1158: 
                   1159:                        PHP_SAFE_FD_SET(this_fd, fds);
                   1160: 
                   1161:                        if (this_fd > *max_fd) {
                   1162:                                *max_fd = this_fd;
                   1163:                        }
                   1164:                        cnt++;
                   1165:                }
                   1166:                p++;
                   1167:        }
                   1168:        return cnt ? 1 : 0;
                   1169: }
                   1170: 
1.1.1.2   misho    1171: static int mysqlnd_stream_array_from_fd_set(MYSQLND ** conn_array, fd_set * fds TSRMLS_DC)
1.1       misho    1172: {
                   1173:        php_socket_t this_fd;
1.1.1.4 ! misho    1174:        php_stream *stream = NULL;
1.1       misho    1175:        int ret = 0;
                   1176:        zend_bool disproportion = FALSE;
                   1177: 
                   1178: 
                   1179:        MYSQLND **fwd = conn_array, **bckwd = conn_array;
                   1180: 
                   1181:        while (*fwd) {
1.1.1.4 ! misho    1182:                stream = (*fwd)->data->net->stream;
        !          1183:                if (stream != NULL && SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL,
1.1       misho    1184:                                                                                (void*)&this_fd, 1) && this_fd >= 0) {
                   1185:                        if (PHP_SAFE_FD_ISSET(this_fd, fds)) {
                   1186:                                if (disproportion) {
                   1187:                                        *bckwd = *fwd;
                   1188:                                }
                   1189:                                bckwd++;
                   1190:                                fwd++;
                   1191:                                ret++;
                   1192:                                continue;
                   1193:                        }
                   1194:                }
                   1195:                disproportion = TRUE;
                   1196:                fwd++;
                   1197:        }
                   1198:        *bckwd = NULL;/* NULL-terminate the list */
                   1199: 
                   1200:        return ret;
                   1201: }
                   1202: /* }}} */
                   1203: 
1.1.1.2   misho    1204: 
1.1       misho    1205: #ifndef PHP_WIN32
                   1206: #define php_select(m, r, w, e, t)      select(m, r, w, e, t)
                   1207: #else
                   1208: #include "win32/select.h"
                   1209: #endif
                   1210: 
1.1.1.2   misho    1211: 
1.1       misho    1212: /* {{{ _mysqlnd_poll */
                   1213: PHPAPI enum_func_status
                   1214: _mysqlnd_poll(MYSQLND **r_array, MYSQLND **e_array, MYSQLND ***dont_poll, long sec, long usec, uint * desc_num TSRMLS_DC)
                   1215: {
                   1216:        struct timeval  tv;
                   1217:        struct timeval *tv_p = NULL;
                   1218:        fd_set                  rfds, wfds, efds;
                   1219:        php_socket_t    max_fd = 0;
                   1220:        int                             retval, sets = 0;
                   1221:        int                             set_count, max_set_count = 0;
                   1222: 
1.1.1.2   misho    1223:        DBG_ENTER("_mysqlnd_poll");
1.1       misho    1224:        if (sec < 0 || usec < 0) {
                   1225:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Negative values passed for sec and/or usec");
                   1226:                DBG_RETURN(FAIL);
                   1227:        }
                   1228: 
                   1229:        *dont_poll = mysqlnd_stream_array_check_for_readiness(r_array TSRMLS_CC);
                   1230: 
                   1231:        FD_ZERO(&rfds);
                   1232:        FD_ZERO(&wfds);
                   1233:        FD_ZERO(&efds);
                   1234: 
                   1235:        if (r_array != NULL) {
                   1236:                set_count = mysqlnd_stream_array_to_fd_set(r_array, &rfds, &max_fd TSRMLS_CC);
                   1237:                if (set_count > max_set_count) {
                   1238:                        max_set_count = set_count;
                   1239:                }
                   1240:                sets += set_count;
                   1241:        }
                   1242: 
                   1243:        if (e_array != NULL) {
                   1244:                set_count = mysqlnd_stream_array_to_fd_set(e_array, &efds, &max_fd TSRMLS_CC);
                   1245:                if (set_count > max_set_count) {
                   1246:                        max_set_count = set_count;
                   1247:                }
                   1248:                sets += set_count;
                   1249:        }
                   1250: 
                   1251:        if (!sets) {
                   1252:                php_error_docref(NULL TSRMLS_CC, E_WARNING, *dont_poll ? "All arrays passed are clear":"No stream arrays were passed");
                   1253:                DBG_ERR_FMT(*dont_poll ? "All arrays passed are clear":"No stream arrays were passed");
                   1254:                DBG_RETURN(FAIL);
                   1255:        }
                   1256: 
                   1257:        PHP_SAFE_MAX_FD(max_fd, max_set_count);
                   1258: 
                   1259:        /* Solaris + BSD do not like microsecond values which are >= 1 sec */
                   1260:        if (usec > 999999) {
                   1261:                tv.tv_sec = sec + (usec / 1000000);
                   1262:                tv.tv_usec = usec % 1000000;
                   1263:        } else {
                   1264:                tv.tv_sec = sec;
                   1265:                tv.tv_usec = usec;
                   1266:        }
                   1267: 
                   1268:        tv_p = &tv;
                   1269: 
                   1270:        retval = php_select(max_fd + 1, &rfds, &wfds, &efds, tv_p);
                   1271: 
                   1272:        if (retval == -1) {
                   1273:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to select [%d]: %s (max_fd=%d)",
                   1274:                                                errno, strerror(errno), max_fd);
                   1275:                DBG_RETURN(FAIL);
                   1276:        }
                   1277: 
                   1278:        if (r_array != NULL) {
                   1279:                mysqlnd_stream_array_from_fd_set(r_array, &rfds TSRMLS_CC);
                   1280:        }
                   1281:        if (e_array != NULL) {
                   1282:                mysqlnd_stream_array_from_fd_set(e_array, &efds TSRMLS_CC);
                   1283:        }
                   1284: 
                   1285:        *desc_num = retval;
                   1286:        DBG_RETURN(PASS);
                   1287: }
                   1288: /* }}} */
                   1289: 
                   1290: 
                   1291: /*
                   1292:   COM_FIELD_LIST is special, different from a SHOW FIELDS FROM :
                   1293:   - There is no result set header - status from the command, which
                   1294:     impacts us to allocate big chunk of memory for reading the metadata.
                   1295:   - The EOF packet is consumed by the metadata packet reader.
                   1296: */
                   1297: 
1.1.1.2   misho    1298: /* {{{ mysqlnd_conn_data::list_fields */
1.1       misho    1299: MYSQLND_RES *
1.1.1.2   misho    1300: MYSQLND_METHOD(mysqlnd_conn_data, list_fields)(MYSQLND_CONN_DATA * conn, const char *table, const char *achtung_wild TSRMLS_DC)
1.1       misho    1301: {
1.1.1.2   misho    1302:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, list_fields);
1.1       misho    1303:        /* db + \0 + wild + \0 (for wild) */
1.1.1.2   misho    1304:        zend_uchar buff[MYSQLND_MAX_ALLOWED_DB_LEN * 2 + 1 + 1], *p;
1.1       misho    1305:        size_t table_len, wild_len;
1.1.1.2   misho    1306:        MYSQLND_RES * result = NULL;
                   1307:        DBG_ENTER("mysqlnd_conn_data::list_fields");
1.1       misho    1308:        DBG_INF_FMT("conn=%llu table=%s wild=%s", conn->thread_id, table? table:"",achtung_wild? achtung_wild:"");
                   1309: 
1.1.1.2   misho    1310:        if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   1311:                do {
                   1312:                        p = buff;
                   1313:                        if (table && (table_len = strlen(table))) {
                   1314:                                size_t to_copy = MIN(table_len, MYSQLND_MAX_ALLOWED_DB_LEN);
                   1315:                                memcpy(p, table, to_copy);
                   1316:                                p += to_copy;
                   1317:                                *p++ = '\0';
                   1318:                        }
                   1319: 
                   1320:                        if (achtung_wild && (wild_len = strlen(achtung_wild))) {
                   1321:                                size_t to_copy = MIN(wild_len, MYSQLND_MAX_ALLOWED_DB_LEN);
                   1322:                                memcpy(p, achtung_wild, to_copy);
                   1323:                                p += to_copy;
                   1324:                                *p++ = '\0';
                   1325:                        }
                   1326: 
                   1327:                        if (PASS != conn->m->simple_command(conn, COM_FIELD_LIST, buff, p - buff,
                   1328:                                                                                           PROT_LAST /* we will handle the OK packet*/,
                   1329:                                                                                           FALSE, TRUE TSRMLS_CC)) {
                   1330:                                conn->m->local_tx_end(conn, 0, FAIL TSRMLS_CC);
                   1331:                                break;
                   1332:                        }
1.1       misho    1333: 
1.1.1.2   misho    1334:                        /*
                   1335:                           Prepare for the worst case.
                   1336:                           MyISAM goes to 2500 BIT columns, double it for safety.
                   1337:                        */
                   1338:                        result = conn->m->result_init(5000, conn->persistent TSRMLS_CC);
                   1339:                        if (!result) {
                   1340:                                break;
                   1341:                        }
1.1       misho    1342: 
1.1.1.2   misho    1343:                        if (FAIL == result->m.read_result_metadata(result, conn TSRMLS_CC)) {
1.1.1.3   misho    1344:                                DBG_ERR("Error occurred while reading metadata");
1.1.1.2   misho    1345:                                result->m.free_result(result, TRUE TSRMLS_CC);
                   1346:                                result = NULL;
                   1347:                                break;
                   1348:                        }
1.1       misho    1349: 
1.1.1.2   misho    1350:                        result->type = MYSQLND_RES_NORMAL;
                   1351:                        result->m.fetch_row = result->m.fetch_row_normal_unbuffered;
                   1352:                        result->unbuf = mnd_ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
                   1353:                        if (!result->unbuf) {
                   1354:                                /* OOM */
                   1355:                                SET_OOM_ERROR(*conn->error_info);
                   1356:                                result->m.free_result(result, TRUE TSRMLS_CC);
                   1357:                                result = NULL;
                   1358:                                break;
                   1359:                        }
                   1360:                        result->unbuf->eof_reached = TRUE;
                   1361:                } while (0);
                   1362:                conn->m->local_tx_end(conn, this_func, result == NULL? FAIL:PASS TSRMLS_CC);
1.1       misho    1363:        }
                   1364: 
                   1365:        DBG_RETURN(result);
                   1366: }
                   1367: /* }}} */
                   1368: 
                   1369: 
1.1.1.2   misho    1370: /* {{{ mysqlnd_conn_data::list_method */
1.1       misho    1371: MYSQLND_RES *
1.1.1.2   misho    1372: 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    1373: {
1.1.1.2   misho    1374:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, list_method);
                   1375:        char * show_query = NULL;
1.1       misho    1376:        size_t show_query_len;
1.1.1.2   misho    1377:        MYSQLND_RES * result = NULL;
1.1       misho    1378: 
1.1.1.2   misho    1379:        DBG_ENTER("mysqlnd_conn_data::list_method");
1.1       misho    1380:        DBG_INF_FMT("conn=%llu query=%s wild=%u", conn->thread_id, query, achtung_wild);
                   1381: 
1.1.1.2   misho    1382:        if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   1383:                if (par1) {
                   1384:                        if (achtung_wild) {
                   1385:                                show_query_len = mnd_sprintf(&show_query, 0, query, par1, achtung_wild);
                   1386:                        } else {
                   1387:                                show_query_len = mnd_sprintf(&show_query, 0, query, par1);
                   1388:                        }
1.1       misho    1389:                } else {
1.1.1.2   misho    1390:                        if (achtung_wild) {
                   1391:                                show_query_len = mnd_sprintf(&show_query, 0, query, achtung_wild);
                   1392:                        } else {
                   1393:                                show_query_len = strlen(show_query = (char *)query);
                   1394:                        }
1.1       misho    1395:                }
                   1396: 
1.1.1.2   misho    1397:                if (PASS == conn->m->query(conn, show_query, show_query_len TSRMLS_CC)) {
                   1398:                        result = conn->m->store_result(conn TSRMLS_CC);
                   1399:                }
                   1400:                if (show_query != query) {
                   1401:                        mnd_sprintf_free(show_query);
                   1402:                }
                   1403:                conn->m->local_tx_end(conn, this_func, result == NULL? FAIL:PASS TSRMLS_CC);
1.1       misho    1404:        }
                   1405:        DBG_RETURN(result);
                   1406: }
                   1407: /* }}} */
                   1408: 
                   1409: 
1.1.1.2   misho    1410: /* {{{ mysqlnd_conn_data::errno */
1.1       misho    1411: static unsigned int
1.1.1.2   misho    1412: MYSQLND_METHOD(mysqlnd_conn_data, errno)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1413: {
1.1.1.2   misho    1414:        return conn->error_info->error_no;
1.1       misho    1415: }
                   1416: /* }}} */
                   1417: 
                   1418: 
1.1.1.2   misho    1419: /* {{{ mysqlnd_conn_data::error */
1.1       misho    1420: static const char *
1.1.1.2   misho    1421: MYSQLND_METHOD(mysqlnd_conn_data, error)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1422: {
1.1.1.2   misho    1423:        return conn->error_info->error;
1.1       misho    1424: }
                   1425: /* }}} */
                   1426: 
                   1427: 
1.1.1.2   misho    1428: /* {{{ mysqlnd_conn_data::sqlstate */
1.1       misho    1429: static const char *
1.1.1.2   misho    1430: MYSQLND_METHOD(mysqlnd_conn_data, sqlstate)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1431: {
1.1.1.2   misho    1432:        return conn->error_info->sqlstate[0] ? conn->error_info->sqlstate:MYSQLND_SQLSTATE_NULL;
1.1       misho    1433: }
                   1434: /* }}} */
                   1435: 
                   1436: 
                   1437: /* {{{ mysqlnd_old_escape_string */
1.1.1.2   misho    1438: PHPAPI ulong 
                   1439: mysqlnd_old_escape_string(char * newstr, const char * escapestr, size_t escapestr_len TSRMLS_DC)
1.1       misho    1440: {
                   1441:        DBG_ENTER("mysqlnd_old_escape_string");
                   1442:        DBG_RETURN(mysqlnd_cset_escape_slashes(mysqlnd_find_charset_name("latin1"), newstr, escapestr, escapestr_len TSRMLS_CC));
                   1443: }
                   1444: /* }}} */
                   1445: 
1.1.1.2   misho    1446: 
                   1447: /* {{{ mysqlnd_conn_data::ssl_set */
1.1       misho    1448: static enum_func_status
1.1.1.2   misho    1449: MYSQLND_METHOD(mysqlnd_conn_data, ssl_set)(MYSQLND_CONN_DATA * const conn, const char * key, const char * const cert,
                   1450:                                                                          const char * const ca, const char * const capath, const char * const cipher TSRMLS_DC)
1.1       misho    1451: {
1.1.1.2   misho    1452:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, ssl_set);
                   1453:        enum_func_status ret = FAIL;
                   1454:        DBG_ENTER("mysqlnd_conn_data::ssl_set");
                   1455: 
                   1456:        if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   1457:                ret = (PASS == conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_KEY, key TSRMLS_CC) &&
                   1458:                        PASS == conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CERT, cert TSRMLS_CC) &&
                   1459:                        PASS == conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CA, ca TSRMLS_CC) &&
                   1460:                        PASS == conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CAPATH, capath TSRMLS_CC) &&
                   1461:                        PASS == conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CIPHER, cipher TSRMLS_CC)) ? PASS : FAIL;
1.1       misho    1462: 
1.1.1.2   misho    1463:                conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);
                   1464:        }
                   1465:        DBG_RETURN(ret);
                   1466: }
                   1467: /* }}} */
1.1       misho    1468: 
1.1.1.2   misho    1469: 
                   1470: /* {{{ mysqlnd_conn_data::escape_string */
1.1       misho    1471: static ulong
1.1.1.2   misho    1472: 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    1473: {
1.1.1.2   misho    1474:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, escape_string);
1.1.1.4 ! misho    1475:        ulong ret = FAIL;
1.1.1.2   misho    1476:        DBG_ENTER("mysqlnd_conn_data::escape_string");
1.1       misho    1477:        DBG_INF_FMT("conn=%llu", conn->thread_id);
1.1.1.2   misho    1478: 
                   1479:        if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   1480:                if (conn->upsert_status->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES) {
                   1481:                        ret = mysqlnd_cset_escape_quotes(conn->charset, newstr, escapestr, escapestr_len TSRMLS_CC);
                   1482:                } else {
                   1483:                        ret = mysqlnd_cset_escape_slashes(conn->charset, newstr, escapestr, escapestr_len TSRMLS_CC);
                   1484:                }
                   1485:                conn->m->local_tx_end(conn, this_func, PASS TSRMLS_CC);
1.1       misho    1486:        }
1.1.1.2   misho    1487:        DBG_RETURN(ret);
1.1       misho    1488: }
                   1489: /* }}} */
                   1490: 
                   1491: 
1.1.1.2   misho    1492: /* {{{ mysqlnd_conn_data::dump_debug_info */
1.1       misho    1493: static enum_func_status
1.1.1.2   misho    1494: MYSQLND_METHOD(mysqlnd_conn_data, dump_debug_info)(MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1495: {
1.1.1.2   misho    1496:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, server_dump_debug_information);
                   1497:        enum_func_status ret = FAIL;
                   1498:        DBG_ENTER("mysqlnd_conn_data::dump_debug_info");
1.1       misho    1499:        DBG_INF_FMT("conn=%llu", conn->thread_id);
1.1.1.2   misho    1500:        if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   1501:                ret = conn->m->simple_command(conn, COM_DEBUG, NULL, 0, PROT_EOF_PACKET, FALSE, TRUE TSRMLS_CC);
                   1502: 
                   1503:                conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);
                   1504:        }
                   1505: 
                   1506:        DBG_RETURN(ret);
1.1       misho    1507: }
                   1508: /* }}} */
                   1509: 
                   1510: 
1.1.1.2   misho    1511: /* {{{ mysqlnd_conn_data::select_db */
1.1       misho    1512: static enum_func_status
1.1.1.2   misho    1513: 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    1514: {
1.1.1.2   misho    1515:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, select_db);
                   1516:        enum_func_status ret = FAIL;
1.1       misho    1517: 
1.1.1.2   misho    1518:        DBG_ENTER("mysqlnd_conn_data::select_db");
1.1       misho    1519:        DBG_INF_FMT("conn=%llu db=%s", conn->thread_id, db);
                   1520: 
1.1.1.2   misho    1521:        if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   1522:                ret = conn->m->simple_command(conn, COM_INIT_DB, (zend_uchar*) db, db_len, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC);
                   1523:                /*
                   1524:                  The server sends 0 but libmysql doesn't read it and has established
                   1525:                  a protocol of giving back -1. Thus we have to follow it :(
                   1526:                */
                   1527:                SET_ERROR_AFF_ROWS(conn);
                   1528:                if (ret == PASS) {
                   1529:                        if (conn->connect_or_select_db) {
                   1530:                                mnd_pefree(conn->connect_or_select_db, conn->persistent);
                   1531:                        }
                   1532:                        conn->connect_or_select_db = mnd_pestrndup(db, db_len, conn->persistent);
                   1533:                        conn->connect_or_select_db_len = db_len;
                   1534:                        if (!conn->connect_or_select_db) {
                   1535:                                /* OOM */
                   1536:                                SET_OOM_ERROR(*conn->error_info);
                   1537:                                ret = FAIL;
                   1538:                        }
1.1       misho    1539:                }
1.1.1.2   misho    1540:                conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);
1.1       misho    1541:        }
                   1542:        DBG_RETURN(ret);
                   1543: }
                   1544: /* }}} */
                   1545: 
                   1546: 
1.1.1.2   misho    1547: /* {{{ mysqlnd_conn_data::ping */
1.1       misho    1548: static enum_func_status
1.1.1.2   misho    1549: MYSQLND_METHOD(mysqlnd_conn_data, ping)(MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1550: {
1.1.1.2   misho    1551:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, ping);
                   1552:        enum_func_status ret = FAIL;
1.1       misho    1553: 
1.1.1.2   misho    1554:        DBG_ENTER("mysqlnd_conn_data::ping");
1.1       misho    1555:        DBG_INF_FMT("conn=%llu", conn->thread_id);
                   1556: 
1.1.1.2   misho    1557:        if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   1558:                ret = conn->m->simple_command(conn, COM_PING, NULL, 0, PROT_OK_PACKET, TRUE, TRUE TSRMLS_CC);
                   1559:                /*
                   1560:                  The server sends 0 but libmysql doesn't read it and has established
                   1561:                  a protocol of giving back -1. Thus we have to follow it :(
                   1562:                */
                   1563:                SET_ERROR_AFF_ROWS(conn);
1.1       misho    1564: 
1.1.1.2   misho    1565:                conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);
                   1566:        }
1.1       misho    1567:        DBG_INF_FMT("ret=%u", ret);
                   1568:        DBG_RETURN(ret);
                   1569: }
                   1570: /* }}} */
                   1571: 
                   1572: 
1.1.1.2   misho    1573: /* {{{ mysqlnd_conn_data::statistic */
1.1       misho    1574: static enum_func_status
1.1.1.2   misho    1575: MYSQLND_METHOD(mysqlnd_conn_data, statistic)(MYSQLND_CONN_DATA * conn, char **message, unsigned int * message_len TSRMLS_DC)
1.1       misho    1576: {
1.1.1.2   misho    1577:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, get_server_statistics);
                   1578:        enum_func_status ret = FAIL;
1.1       misho    1579:        MYSQLND_PACKET_STATS * stats_header;
                   1580: 
1.1.1.2   misho    1581:        DBG_ENTER("mysqlnd_conn_data::statistic");
1.1       misho    1582:        DBG_INF_FMT("conn=%llu", conn->thread_id);
                   1583: 
1.1.1.2   misho    1584:        if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   1585:                do {
                   1586:                        ret = conn->m->simple_command(conn, COM_STATISTICS, NULL, 0, PROT_LAST, FALSE, TRUE TSRMLS_CC);
                   1587:                        if (FAIL == ret) {
                   1588:                                break;
                   1589:                        }
                   1590:                        stats_header = conn->protocol->m.get_stats_packet(conn->protocol, FALSE TSRMLS_CC);
                   1591:                        if (!stats_header) {
                   1592:                                SET_OOM_ERROR(*conn->error_info);
                   1593:                                break;
                   1594:                        }
1.1       misho    1595: 
1.1.1.2   misho    1596:                        if (PASS == (ret = PACKET_READ(stats_header, conn))) {
                   1597:                                /* will be freed by Zend, thus don't use the mnd_ allocator */
                   1598:                                *message = estrndup(stats_header->message, stats_header->message_len); 
                   1599:                                *message_len = stats_header->message_len;
                   1600:                                DBG_INF(*message);
                   1601:                        }
                   1602:                        PACKET_FREE(stats_header);
                   1603:                } while (0);
1.1       misho    1604: 
1.1.1.2   misho    1605:                conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);
                   1606:        }
                   1607:        DBG_RETURN(ret);
1.1       misho    1608: }
                   1609: /* }}} */
                   1610: 
                   1611: 
1.1.1.2   misho    1612: /* {{{ mysqlnd_conn_data::kill */
1.1       misho    1613: static enum_func_status
1.1.1.2   misho    1614: MYSQLND_METHOD(mysqlnd_conn_data, kill)(MYSQLND_CONN_DATA * conn, unsigned int pid TSRMLS_DC)
1.1       misho    1615: {
1.1.1.2   misho    1616:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, kill_connection);
                   1617:        enum_func_status ret = FAIL;
                   1618:        zend_uchar buff[4];
1.1       misho    1619: 
1.1.1.2   misho    1620:        DBG_ENTER("mysqlnd_conn_data::kill");
1.1       misho    1621:        DBG_INF_FMT("conn=%llu pid=%u", conn->thread_id, pid);
                   1622: 
1.1.1.2   misho    1623:        if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   1624:                int4store(buff, pid);
1.1       misho    1625: 
1.1.1.2   misho    1626:                /* If we kill ourselves don't expect OK packet, PROT_LAST will skip it */
                   1627:                if (pid != conn->thread_id) {
                   1628:                        ret = conn->m->simple_command(conn, COM_PROCESS_KILL, buff, 4, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC);
                   1629:                        /*
                   1630:                          The server sends 0 but libmysql doesn't read it and has established
                   1631:                          a protocol of giving back -1. Thus we have to follow it :(
                   1632:                        */
                   1633:                        SET_ERROR_AFF_ROWS(conn);
                   1634:                } else if (PASS == (ret = conn->m->simple_command(conn, COM_PROCESS_KILL, buff, 4, PROT_LAST, FALSE, TRUE TSRMLS_CC))) {
                   1635:                        CONN_SET_STATE(conn, CONN_QUIT_SENT);
                   1636:                }
                   1637: 
                   1638:                conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);
1.1       misho    1639:        }
                   1640:        DBG_RETURN(ret);
                   1641: }
                   1642: /* }}} */
                   1643: 
                   1644: 
1.1.1.2   misho    1645: /* {{{ mysqlnd_conn_data::set_charset */
1.1       misho    1646: static enum_func_status
1.1.1.2   misho    1647: MYSQLND_METHOD(mysqlnd_conn_data, set_charset)(MYSQLND_CONN_DATA * const conn, const char * const csname TSRMLS_DC)
1.1       misho    1648: {
1.1.1.2   misho    1649:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, set_charset);
                   1650:        enum_func_status ret = FAIL;
1.1       misho    1651:        const MYSQLND_CHARSET * const charset = mysqlnd_find_charset_name(csname);
                   1652: 
1.1.1.2   misho    1653:        DBG_ENTER("mysqlnd_conn_data::set_charset");
1.1       misho    1654:        DBG_INF_FMT("conn=%llu cs=%s", conn->thread_id, csname);
                   1655: 
                   1656:        if (!charset) {
1.1.1.2   misho    1657:                SET_CLIENT_ERROR(*conn->error_info, CR_CANT_FIND_CHARSET, UNKNOWN_SQLSTATE,
1.1       misho    1658:                                                 "Invalid characterset or character set not supported");
1.1.1.2   misho    1659:                DBG_RETURN(ret);
1.1       misho    1660:        }
                   1661: 
1.1.1.2   misho    1662:        if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   1663:                char * query;
                   1664:                size_t query_len = mnd_sprintf(&query, 0, "SET NAMES %s", csname);
1.1       misho    1665: 
1.1.1.2   misho    1666:                if (FAIL == (ret = conn->m->query(conn, query, query_len TSRMLS_CC))) {
                   1667:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error executing query");
                   1668:                } else if (conn->error_info->error_no) {
                   1669:                        ret = FAIL;
                   1670:                } else {
                   1671:                        conn->charset = charset;
                   1672:                }
                   1673:                mnd_sprintf_free(query);
                   1674: 
                   1675:                conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);
1.1       misho    1676:        }
                   1677: 
                   1678:        DBG_INF(ret == PASS? "PASS":"FAIL");
                   1679:        DBG_RETURN(ret);
                   1680: }
                   1681: /* }}} */
                   1682: 
                   1683: 
1.1.1.2   misho    1684: /* {{{ mysqlnd_conn_data::refresh */
1.1       misho    1685: static enum_func_status
1.1.1.2   misho    1686: MYSQLND_METHOD(mysqlnd_conn_data, refresh)(MYSQLND_CONN_DATA * const conn, uint8_t options TSRMLS_DC)
1.1       misho    1687: {
1.1.1.2   misho    1688:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, refresh_server);
                   1689:        enum_func_status ret = FAIL;
1.1       misho    1690:        zend_uchar bits[1];
1.1.1.2   misho    1691:        DBG_ENTER("mysqlnd_conn_data::refresh");
1.1       misho    1692:        DBG_INF_FMT("conn=%llu options=%lu", conn->thread_id, options);
                   1693: 
1.1.1.2   misho    1694:        if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   1695:                int1store(bits, options);
                   1696: 
                   1697:                ret = conn->m->simple_command(conn, COM_REFRESH, bits, 1, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC);
1.1       misho    1698: 
1.1.1.2   misho    1699:                conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);
                   1700:        }
                   1701:        DBG_RETURN(ret);
1.1       misho    1702: }
                   1703: /* }}} */
                   1704: 
                   1705: 
1.1.1.2   misho    1706: /* {{{ mysqlnd_conn_data::shutdown */
1.1       misho    1707: static enum_func_status
1.1.1.2   misho    1708: MYSQLND_METHOD(mysqlnd_conn_data, shutdown)(MYSQLND_CONN_DATA * const conn, uint8_t level TSRMLS_DC)
1.1       misho    1709: {
1.1.1.2   misho    1710:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, shutdown_server);
                   1711:        enum_func_status ret = FAIL;
1.1       misho    1712:        zend_uchar bits[1];
1.1.1.2   misho    1713:        DBG_ENTER("mysqlnd_conn_data::shutdown");
1.1       misho    1714:        DBG_INF_FMT("conn=%llu level=%lu", conn->thread_id, level);
                   1715: 
1.1.1.2   misho    1716:        if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   1717:                int1store(bits, level);
1.1       misho    1718: 
1.1.1.2   misho    1719:                ret = conn->m->simple_command(conn, COM_SHUTDOWN, bits, 1, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC);
                   1720: 
                   1721:                conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);
                   1722:        }
                   1723:        DBG_RETURN(ret);        
1.1       misho    1724: }
                   1725: /* }}} */
                   1726: 
                   1727: 
                   1728: /* {{{ mysqlnd_send_close */
                   1729: static enum_func_status
1.1.1.2   misho    1730: MYSQLND_METHOD(mysqlnd_conn_data, send_close)(MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1731: {
                   1732:        enum_func_status ret = PASS;
                   1733: 
                   1734:        DBG_ENTER("mysqlnd_send_close");
                   1735:        DBG_INF_FMT("conn=%llu conn->net->stream->abstract=%p",
                   1736:                                conn->thread_id, conn->net->stream? conn->net->stream->abstract:NULL);
                   1737: 
1.1.1.2   misho    1738:        if (CONN_GET_STATE(conn) >= CONN_READY) {
                   1739:                MYSQLND_DEC_CONN_STATISTIC(conn->stats, STAT_OPENED_CONNECTIONS);
                   1740:                if (conn->persistent) {
                   1741:                        MYSQLND_DEC_CONN_STATISTIC(conn->stats, STAT_OPENED_PERSISTENT_CONNECTIONS);
                   1742:                }
                   1743:        }
1.1       misho    1744:        switch (CONN_GET_STATE(conn)) {
                   1745:                case CONN_READY:
                   1746:                        DBG_INF("Connection clean, sending COM_QUIT");
                   1747:                        if (conn->net->stream) {
1.1.1.2   misho    1748:                                ret = conn->m->simple_command(conn, COM_QUIT, NULL, 0, PROT_LAST, TRUE, TRUE TSRMLS_CC);
1.1       misho    1749:                        }
                   1750:                        /* Do nothing */
                   1751:                        break;
                   1752:                case CONN_SENDING_LOAD_DATA:
                   1753:                        /*
                   1754:                          Don't send COM_QUIT if we are in a middle of a LOAD DATA or we
                   1755:                          will crash (assert) a debug server.
                   1756:                        */
                   1757:                case CONN_NEXT_RESULT_PENDING:
                   1758:                case CONN_QUERY_SENT:
                   1759:                case CONN_FETCHING_DATA:
                   1760:                        MYSQLND_INC_GLOBAL_STATISTIC(STAT_CLOSE_IN_MIDDLE);
                   1761:                        DBG_ERR_FMT("Brutally closing connection [%p][%s]", conn, conn->scheme);
                   1762:                        /*
                   1763:                          Do nothing, the connection will be brutally closed
                   1764:                          and the server will catch it and free close from its side.
                   1765:                        */
                   1766:                case CONN_ALLOCED:
                   1767:                        /*
                   1768:                          Allocated but not connected or there was failure when trying
                   1769:                          to connect with pre-allocated connect.
                   1770: 
                   1771:                          Fall-through
                   1772:                        */
                   1773:                case CONN_QUIT_SENT:
                   1774:                        /* The user has killed its own connection */
                   1775:                        break;
                   1776:        }
                   1777:        /*
                   1778:          We hold one reference, and every other object which needs the
                   1779:          connection does increase it by 1.
                   1780:        */
                   1781:        CONN_SET_STATE(conn, CONN_QUIT_SENT);
                   1782: 
                   1783:        DBG_RETURN(ret);
                   1784: }
                   1785: /* }}} */
                   1786: 
                   1787: 
1.1.1.2   misho    1788: /* {{{ mysqlnd_conn_data::get_reference */
                   1789: static MYSQLND_CONN_DATA *
                   1790: MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, get_reference)(MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1791: {
1.1.1.2   misho    1792:        DBG_ENTER("mysqlnd_conn_data::get_reference");
1.1       misho    1793:        ++conn->refcount;
                   1794:        DBG_INF_FMT("conn=%llu new_refcount=%u", conn->thread_id, conn->refcount);
                   1795:        DBG_RETURN(conn);
                   1796: }
                   1797: /* }}} */
                   1798: 
                   1799: 
1.1.1.2   misho    1800: /* {{{ mysqlnd_conn_data::free_reference */
1.1       misho    1801: static enum_func_status
1.1.1.2   misho    1802: MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, free_reference)(MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1803: {
                   1804:        enum_func_status ret = PASS;
1.1.1.2   misho    1805:        DBG_ENTER("mysqlnd_conn_data::free_reference");
1.1       misho    1806:        DBG_INF_FMT("conn=%llu old_refcount=%u", conn->thread_id, conn->refcount);
                   1807:        if (!(--conn->refcount)) {
                   1808:                /*
                   1809:                  No multithreading issues as we don't share the connection :)
                   1810:                  This will free the object too, of course because references has
                   1811:                  reached zero.
                   1812:                */
                   1813:                ret = conn->m->send_close(conn TSRMLS_CC);
                   1814:                conn->m->dtor(conn TSRMLS_CC);
                   1815:        }
                   1816:        DBG_RETURN(ret);
                   1817: }
                   1818: /* }}} */
                   1819: 
                   1820: 
1.1.1.2   misho    1821: /* {{{ mysqlnd_conn_data::get_state */
1.1       misho    1822: static enum mysqlnd_connection_state
1.1.1.2   misho    1823: MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, get_state)(MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1824: {
1.1.1.2   misho    1825:        DBG_ENTER("mysqlnd_conn_data::get_state");
1.1       misho    1826:        DBG_RETURN(conn->state);
                   1827: }
                   1828: /* }}} */
                   1829: 
                   1830: 
1.1.1.2   misho    1831: /* {{{ mysqlnd_conn_data::set_state */
1.1       misho    1832: static void
1.1.1.2   misho    1833: MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, set_state)(MYSQLND_CONN_DATA * const conn, enum mysqlnd_connection_state new_state TSRMLS_DC)
1.1       misho    1834: {
1.1.1.2   misho    1835:        DBG_ENTER("mysqlnd_conn_data::set_state");
1.1       misho    1836:        DBG_INF_FMT("New state=%u", new_state);
                   1837:        conn->state = new_state;
                   1838:        DBG_VOID_RETURN;
                   1839: }
                   1840: /* }}} */
                   1841: 
                   1842: 
1.1.1.2   misho    1843: /* {{{ mysqlnd_conn_data::field_count */
1.1       misho    1844: static unsigned int
1.1.1.2   misho    1845: MYSQLND_METHOD(mysqlnd_conn_data, field_count)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1846: {
                   1847:        return conn->field_count;
                   1848: }
                   1849: /* }}} */
                   1850: 
                   1851: 
1.1.1.2   misho    1852: /* {{{ mysqlnd_conn_data::server_status */
                   1853: static unsigned int
                   1854: MYSQLND_METHOD(mysqlnd_conn_data, server_status)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC)
                   1855: {
                   1856:        return conn->upsert_status->server_status;
                   1857: }
                   1858: /* }}} */
                   1859: 
                   1860: 
                   1861: /* {{{ mysqlnd_conn_data::insert_id */
1.1       misho    1862: static uint64_t
1.1.1.2   misho    1863: MYSQLND_METHOD(mysqlnd_conn_data, insert_id)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1864: {
1.1.1.2   misho    1865:        return conn->upsert_status->last_insert_id;
1.1       misho    1866: }
                   1867: /* }}} */
                   1868: 
                   1869: 
1.1.1.2   misho    1870: /* {{{ mysqlnd_conn_data::affected_rows */
1.1       misho    1871: static uint64_t
1.1.1.2   misho    1872: MYSQLND_METHOD(mysqlnd_conn_data, affected_rows)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1873: {
1.1.1.2   misho    1874:        return conn->upsert_status->affected_rows;
1.1       misho    1875: }
                   1876: /* }}} */
                   1877: 
                   1878: 
1.1.1.2   misho    1879: /* {{{ mysqlnd_conn_data::warning_count */
1.1       misho    1880: static unsigned int
1.1.1.2   misho    1881: MYSQLND_METHOD(mysqlnd_conn_data, warning_count)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1882: {
1.1.1.2   misho    1883:        return conn->upsert_status->warning_count;
1.1       misho    1884: }
                   1885: /* }}} */
                   1886: 
                   1887: 
1.1.1.2   misho    1888: /* {{{ mysqlnd_conn_data::info */
1.1       misho    1889: static const char *
1.1.1.2   misho    1890: MYSQLND_METHOD(mysqlnd_conn_data, info)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1891: {
                   1892:        return conn->last_message;
                   1893: }
                   1894: /* }}} */
                   1895: 
                   1896: /* {{{ mysqlnd_get_client_info */
                   1897: PHPAPI const char * mysqlnd_get_client_info()
                   1898: {
                   1899:        return MYSQLND_VERSION;
                   1900: }
                   1901: /* }}} */
                   1902: 
                   1903: 
                   1904: /* {{{ mysqlnd_get_client_version */
                   1905: PHPAPI unsigned int mysqlnd_get_client_version()
                   1906: {
                   1907:        return MYSQLND_VERSION_ID;
                   1908: }
                   1909: /* }}} */
                   1910: 
1.1.1.2   misho    1911: 
                   1912: /* {{{ mysqlnd_conn_data::get_server_info */
1.1       misho    1913: static const char *
1.1.1.2   misho    1914: MYSQLND_METHOD(mysqlnd_conn_data, get_server_info)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1915: {
                   1916:        return conn->server_version;
                   1917: }
                   1918: /* }}} */
                   1919: 
                   1920: 
1.1.1.2   misho    1921: /* {{{ mysqlnd_conn_data::get_host_info */
1.1       misho    1922: static const char *
1.1.1.2   misho    1923: MYSQLND_METHOD(mysqlnd_conn_data, get_host_info)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1924: {
                   1925:        return conn->host_info;
                   1926: }
                   1927: /* }}} */
                   1928: 
                   1929: 
1.1.1.2   misho    1930: /* {{{ mysqlnd_conn_data::get_proto_info */
1.1       misho    1931: static unsigned int
1.1.1.2   misho    1932: MYSQLND_METHOD(mysqlnd_conn_data, get_proto_info)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1933: {
                   1934:        return conn->protocol_version;
                   1935: }
                   1936: /* }}} */
                   1937: 
                   1938: 
1.1.1.2   misho    1939: /* {{{ mysqlnd_conn_data::charset_name */
1.1       misho    1940: static const char *
1.1.1.2   misho    1941: MYSQLND_METHOD(mysqlnd_conn_data, charset_name)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1942: {
                   1943:        return conn->charset->name;
                   1944: }
                   1945: /* }}} */
                   1946: 
                   1947: 
1.1.1.2   misho    1948: /* {{{ mysqlnd_conn_data::thread_id */
1.1       misho    1949: static uint64_t
1.1.1.2   misho    1950: MYSQLND_METHOD(mysqlnd_conn_data, thread_id)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1951: {
                   1952:        return conn->thread_id;
                   1953: }
                   1954: /* }}} */
                   1955: 
                   1956: 
1.1.1.2   misho    1957: /* {{{ mysqlnd_conn_data::get_server_version */
1.1       misho    1958: static unsigned long
1.1.1.2   misho    1959: MYSQLND_METHOD(mysqlnd_conn_data, get_server_version)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1960: {
                   1961:        long major, minor, patch;
                   1962:        char *p;
                   1963: 
                   1964:        if (!(p = conn->server_version)) {
                   1965:                return 0;
                   1966:        }
                   1967: 
                   1968:        major = strtol(p, &p, 10);
                   1969:        p += 1; /* consume the dot */
                   1970:        minor = strtol(p, &p, 10);
                   1971:        p += 1; /* consume the dot */
                   1972:        patch = strtol(p, &p, 10);
                   1973: 
                   1974:        return (unsigned long)(major * 10000L + (unsigned long)(minor * 100L + patch));
                   1975: }
                   1976: /* }}} */
                   1977: 
                   1978: 
1.1.1.2   misho    1979: /* {{{ mysqlnd_conn_data::more_results */
1.1       misho    1980: static zend_bool
1.1.1.2   misho    1981: MYSQLND_METHOD(mysqlnd_conn_data, more_results)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1982: {
1.1.1.2   misho    1983:        DBG_ENTER("mysqlnd_conn_data::more_results");
1.1       misho    1984:        /* (conn->state == CONN_NEXT_RESULT_PENDING) too */
1.1.1.2   misho    1985:        DBG_RETURN(conn->upsert_status->server_status & SERVER_MORE_RESULTS_EXISTS? TRUE:FALSE);
1.1       misho    1986: }
                   1987: /* }}} */
                   1988: 
                   1989: 
1.1.1.2   misho    1990: /* {{{ mysqlnd_conn_data::next_result */
1.1       misho    1991: static enum_func_status
1.1.1.2   misho    1992: MYSQLND_METHOD(mysqlnd_conn_data, next_result)(MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    1993: {
1.1.1.2   misho    1994:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, next_result);
                   1995:        enum_func_status ret = FAIL;
1.1       misho    1996: 
1.1.1.2   misho    1997:        DBG_ENTER("mysqlnd_conn_data::next_result");
1.1       misho    1998:        DBG_INF_FMT("conn=%llu", conn->thread_id);
                   1999: 
1.1.1.2   misho    2000:        if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   2001:                do {
                   2002:                        if (CONN_GET_STATE(conn) != CONN_NEXT_RESULT_PENDING) {
                   2003:                                break;
                   2004:                        }
1.1       misho    2005: 
1.1.1.2   misho    2006:                        SET_EMPTY_ERROR(*conn->error_info);
                   2007:                        SET_ERROR_AFF_ROWS(conn);
                   2008:                        /*
                   2009:                          We are sure that there is a result set, since conn->state is set accordingly
                   2010:                          in mysqlnd_store_result() or mysqlnd_fetch_row_unbuffered()
                   2011:                        */
                   2012:                        if (FAIL == (ret = conn->m->query_read_result_set_header(conn, NULL TSRMLS_CC))) {
                   2013:                                /*
                   2014:                                  There can be an error in the middle of a multi-statement, which will cancel the multi-statement.
                   2015:                                  So there are no more results and we should just return FALSE, error_no has been set
                   2016:                                */
                   2017:                                if (!conn->error_info->error_no) {
                   2018:                                        DBG_ERR_FMT("Serious error. %s::%u", __FILE__, __LINE__);
                   2019:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Serious error. PID=%d", getpid());
                   2020:                                        CONN_SET_STATE(conn, CONN_QUIT_SENT);
                   2021:                                } else {
                   2022:                                        DBG_INF_FMT("Error from the server : (%u) %s", conn->error_info->error_no, conn->error_info->error);
                   2023:                                }
                   2024:                                break;
                   2025:                        }
                   2026:                        if (conn->last_query_type == QUERY_UPSERT && conn->upsert_status->affected_rows) {
                   2027:                                MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn->stats, STAT_ROWS_AFFECTED_NORMAL, conn->upsert_status->affected_rows);
                   2028:                        }
                   2029:                } while (0);
                   2030:                conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);
1.1       misho    2031:        }
                   2032: 
                   2033:        DBG_RETURN(ret);
                   2034: }
                   2035: /* }}} */
                   2036: 
                   2037: 
                   2038: /* {{{ mysqlnd_field_type_name */
                   2039: PHPAPI const char *mysqlnd_field_type_name(enum mysqlnd_field_types field_type)
                   2040: {
                   2041:        switch(field_type) {
                   2042:                case FIELD_TYPE_STRING:
                   2043:                case FIELD_TYPE_VAR_STRING:
                   2044:                        return "string";
                   2045:                case FIELD_TYPE_TINY:
                   2046:                case FIELD_TYPE_SHORT:
                   2047:                case FIELD_TYPE_LONG:
                   2048:                case FIELD_TYPE_LONGLONG:
                   2049:                case FIELD_TYPE_INT24:
                   2050:                        return "int";
                   2051:                case FIELD_TYPE_FLOAT:
                   2052:                case FIELD_TYPE_DOUBLE:
                   2053:                case FIELD_TYPE_DECIMAL:
                   2054:                case FIELD_TYPE_NEWDECIMAL:
                   2055:                        return "real";
                   2056:                case FIELD_TYPE_TIMESTAMP:
                   2057:                        return "timestamp";
                   2058:                case FIELD_TYPE_YEAR:
                   2059:                        return "year";
                   2060:                case FIELD_TYPE_DATE:
                   2061:                case FIELD_TYPE_NEWDATE:
                   2062:                        return "date";
                   2063:                case FIELD_TYPE_TIME:
                   2064:                        return "time";
                   2065:                case FIELD_TYPE_SET:
                   2066:                        return "set";
                   2067:                case FIELD_TYPE_ENUM:
                   2068:                        return "enum";
                   2069:                case FIELD_TYPE_GEOMETRY:
                   2070:                        return "geometry";
                   2071:                case FIELD_TYPE_DATETIME:
                   2072:                        return "datetime";
                   2073:                case FIELD_TYPE_TINY_BLOB:
                   2074:                case FIELD_TYPE_MEDIUM_BLOB:
                   2075:                case FIELD_TYPE_LONG_BLOB:
                   2076:                case FIELD_TYPE_BLOB:
                   2077:                        return "blob";
                   2078:                case FIELD_TYPE_NULL:
                   2079:                        return "null";
                   2080:                case FIELD_TYPE_BIT:
                   2081:                        return "bit";
                   2082:                default:
                   2083:                        return "unknown";
                   2084:        }
                   2085: }
                   2086: /* }}} */
                   2087: 
                   2088: 
1.1.1.2   misho    2089: /* {{{ mysqlnd_conn_data::change_user */
                   2090: static enum_func_status
                   2091: MYSQLND_METHOD(mysqlnd_conn_data, change_user)(MYSQLND_CONN_DATA * const conn,
                   2092:                                                                                  const char * user,
                   2093:                                                                                  const char * passwd,
                   2094:                                                                                  const char * db,
                   2095:                                                                                  zend_bool silent,
                   2096:                                                                                  size_t passwd_len
                   2097:                                                                                  TSRMLS_DC)
                   2098: {
                   2099:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, change_user);
                   2100:        /*
                   2101:          User could be max 16 * 3 (utf8), pass is 20 usually, db is up to 64*3
                   2102:          Stack space is not that expensive, so use a bit more to be protected against
                   2103:          buffer overflows.
                   2104:        */
                   2105:        enum_func_status ret = FAIL;
                   2106:        zend_bool local_tx_started = FALSE;
                   2107: 
                   2108:        DBG_ENTER("mysqlnd_conn_data::change_user");
                   2109:        DBG_INF_FMT("conn=%llu user=%s passwd=%s db=%s silent=%u",
                   2110:                                conn->thread_id, user?user:"", passwd?"***":"null", db?db:"", (silent == TRUE)?1:0 );
                   2111: 
                   2112:        if (PASS != conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   2113:                goto end;
                   2114:        }
                   2115:        local_tx_started = TRUE;
                   2116: 
                   2117:        SET_EMPTY_ERROR(*conn->error_info);
                   2118:        SET_ERROR_AFF_ROWS(conn);
                   2119: 
                   2120:        if (!user) {
                   2121:                user = "";
                   2122:        }
                   2123:        if (!passwd) {
                   2124:                passwd = "";
                   2125:        }
                   2126:        if (!db) {
                   2127:                db = "";
                   2128:        }
                   2129: 
                   2130:        {
                   2131:                zend_bool first_call = TRUE;
                   2132:                char * switch_to_auth_protocol = NULL;
                   2133:                size_t switch_to_auth_protocol_len = 0;
                   2134:                char * requested_protocol = NULL;
                   2135:                zend_uchar * plugin_data;
                   2136:                size_t plugin_data_len;
                   2137: 
                   2138:                plugin_data_len = conn->auth_plugin_data_len;
                   2139:                plugin_data = mnd_emalloc(plugin_data_len);
                   2140:                if (!plugin_data) {
                   2141:                        ret = FAIL;
                   2142:                        goto end;
                   2143:                }
                   2144:                memcpy(plugin_data, conn->auth_plugin_data, plugin_data_len);
                   2145: 
                   2146:                requested_protocol = mnd_pestrdup(conn->options->auth_protocol? conn->options->auth_protocol:"mysql_native_password", FALSE);
                   2147:                if (!requested_protocol) {
                   2148:                        ret = FAIL;
                   2149:                        goto end;
                   2150:                }
                   2151: 
                   2152:                do {
                   2153:                        struct st_mysqlnd_authentication_plugin * auth_plugin;
                   2154:                        {
                   2155:                                char * plugin_name = NULL;
                   2156: 
                   2157:                                mnd_sprintf(&plugin_name, 0, "auth_plugin_%s", requested_protocol);
                   2158: 
                   2159:                                DBG_INF_FMT("looking for %s auth plugin", plugin_name);
                   2160:                                auth_plugin = mysqlnd_plugin_find(plugin_name);
                   2161:                                mnd_sprintf_free(plugin_name);
                   2162: 
                   2163:                                if (!auth_plugin) {
                   2164:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "The server requested authentication method unknown to the client [%s]", requested_protocol);
                   2165:                                        SET_CLIENT_ERROR(*conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "The server requested authentication method umknown to the client");
                   2166:                                        break;
                   2167:                                }
                   2168:                        }
                   2169:                        DBG_INF("plugin found");
                   2170: 
                   2171:                        {
                   2172:                                zend_uchar * switch_to_auth_protocol_data = NULL;
                   2173:                                size_t switch_to_auth_protocol_data_len = 0;
                   2174:                                zend_uchar * scrambled_data = NULL;
                   2175:                                size_t scrambled_data_len = 0;
                   2176: 
                   2177:                                switch_to_auth_protocol = NULL;
                   2178:                                switch_to_auth_protocol_len = 0;
                   2179: 
                   2180:                                if (conn->auth_plugin_data) {
                   2181:                                        mnd_pefree(conn->auth_plugin_data, conn->persistent);
                   2182:                                        conn->auth_plugin_data = NULL;
                   2183:                                }
                   2184:                                conn->auth_plugin_data_len = plugin_data_len;
                   2185:                                conn->auth_plugin_data = mnd_pemalloc(conn->auth_plugin_data_len, conn->persistent);
                   2186:                                if (!conn->auth_plugin_data) {
                   2187:                                        SET_OOM_ERROR(*conn->error_info);
                   2188:                                        ret = FAIL;
                   2189:                                        goto end;
                   2190:                                }
                   2191:                                memcpy(conn->auth_plugin_data, plugin_data, plugin_data_len);
                   2192: 
1.1.1.3   misho    2193:                                DBG_INF_FMT("salt=[%*.s]", plugin_data_len - 1, plugin_data);
1.1.1.2   misho    2194: 
                   2195:                                /* The data should be allocated with malloc() */
                   2196:                                scrambled_data =
                   2197:                                                auth_plugin->methods.get_auth_data(NULL, &scrambled_data_len, conn, user, passwd, passwd_len,
                   2198:                                                                                                                   plugin_data, plugin_data_len, 0, conn->server_capabilities TSRMLS_CC);
                   2199: 
                   2200: 
                   2201:                                ret = mysqlnd_auth_change_user(conn, user, strlen(user), passwd, passwd_len, db, strlen(db), silent,
                   2202:                                                                                           first_call,
                   2203:                                                                                           requested_protocol,
                   2204:                                                                                           scrambled_data, scrambled_data_len,
                   2205:                                                                                           &switch_to_auth_protocol, &switch_to_auth_protocol_len,
                   2206:                                                                                           &switch_to_auth_protocol_data, &switch_to_auth_protocol_data_len
                   2207:                                                                                           TSRMLS_CC);
                   2208: 
                   2209:                                first_call = FALSE;
                   2210:                                free(scrambled_data);
                   2211: 
                   2212:                                DBG_INF_FMT("switch_to_auth_protocol=%s", switch_to_auth_protocol? switch_to_auth_protocol:"n/a");
                   2213:                                if (requested_protocol) {
                   2214:                                        mnd_efree(requested_protocol);
                   2215:                                }
                   2216:                                requested_protocol = switch_to_auth_protocol;
                   2217: 
                   2218:                                if (plugin_data) {
                   2219:                                        mnd_efree(plugin_data);
                   2220:                                }
                   2221:                                plugin_data_len = switch_to_auth_protocol_data_len;
                   2222:                                plugin_data = switch_to_auth_protocol_data;
                   2223:                        }
                   2224:                        DBG_INF_FMT("conn->error_info->error_no = %d", conn->error_info->error_no);
                   2225:                } while (ret == FAIL && conn->error_info->error_no == 0 && switch_to_auth_protocol != NULL);
                   2226:                if (plugin_data) {
                   2227:                        mnd_efree(plugin_data);
                   2228:                }
                   2229:                if (ret == PASS) {
                   2230:                        conn->m->set_client_option(conn, MYSQLND_OPT_AUTH_PROTOCOL, requested_protocol TSRMLS_CC);
                   2231:                }
                   2232:                if (requested_protocol) {
                   2233:                        mnd_efree(requested_protocol);
                   2234:                }
                   2235:        }
                   2236:        /*
                   2237:          Here we should close all statements. Unbuffered queries should not be a
                   2238:          problem as we won't allow sending COM_CHANGE_USER.
                   2239:        */
                   2240: end:
                   2241:        if (TRUE == local_tx_started) {
                   2242:                conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);  
                   2243:        }
                   2244:        DBG_INF(ret == PASS? "PASS":"FAIL");
                   2245:        DBG_RETURN(ret);
                   2246: }
                   2247: /* }}} */
                   2248: 
                   2249: 
                   2250: /* {{{ mysqlnd_conn_data::set_client_option */
1.1       misho    2251: static enum_func_status
1.1.1.2   misho    2252: MYSQLND_METHOD(mysqlnd_conn_data, set_client_option)(MYSQLND_CONN_DATA * const conn,
1.1       misho    2253:                                                                                                enum mysqlnd_option option,
                   2254:                                                                                                const char * const value
                   2255:                                                                                                TSRMLS_DC)
                   2256: {
1.1.1.2   misho    2257:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, set_client_option);
1.1       misho    2258:        enum_func_status ret = PASS;
1.1.1.2   misho    2259:        DBG_ENTER("mysqlnd_conn_data::set_client_option");
1.1       misho    2260:        DBG_INF_FMT("conn=%llu option=%u", conn->thread_id, option);
1.1.1.2   misho    2261: 
                   2262:        if (PASS != conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   2263:                goto end;
                   2264:        }
1.1       misho    2265:        switch (option) {
                   2266:                case MYSQL_OPT_COMPRESS:
                   2267: #ifdef WHEN_SUPPORTED_BY_MYSQLI
                   2268:                case MYSQL_OPT_READ_TIMEOUT:
                   2269:                case MYSQL_OPT_WRITE_TIMEOUT:
                   2270: #endif
                   2271:                case MYSQLND_OPT_SSL_KEY:
                   2272:                case MYSQLND_OPT_SSL_CERT:
                   2273:                case MYSQLND_OPT_SSL_CA:
                   2274:                case MYSQLND_OPT_SSL_CAPATH:
                   2275:                case MYSQLND_OPT_SSL_CIPHER:
                   2276:                case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
                   2277:                case MYSQL_OPT_CONNECT_TIMEOUT:
                   2278:                case MYSQLND_OPT_NET_CMD_BUFFER_SIZE:
                   2279:                case MYSQLND_OPT_NET_READ_BUFFER_SIZE:
                   2280:                        ret = conn->net->m.set_client_option(conn->net, option, value TSRMLS_CC);
                   2281:                        break;
                   2282: #if MYSQLND_UNICODE
                   2283:                case MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE:
1.1.1.2   misho    2284:                        conn->options->numeric_and_datetime_as_unicode = *(unsigned int*) value;
1.1       misho    2285:                        break;
                   2286: #endif
                   2287: #ifdef MYSQLND_STRING_TO_INT_CONVERSION
                   2288:                case MYSQLND_OPT_INT_AND_FLOAT_NATIVE:
1.1.1.2   misho    2289:                        conn->options->int_and_float_native = *(unsigned int*) value;
1.1       misho    2290:                        break;
                   2291: #endif
                   2292:                case MYSQL_OPT_LOCAL_INFILE:
1.1.1.3   misho    2293:                        if (value && (*(unsigned int*) value) ? 1 : 0) {
1.1.1.2   misho    2294:                                conn->options->flags |= CLIENT_LOCAL_FILES;
1.1       misho    2295:                        } else {
1.1.1.2   misho    2296:                                conn->options->flags &= ~CLIENT_LOCAL_FILES;
1.1       misho    2297:                        }
                   2298:                        break;
                   2299:                case MYSQL_INIT_COMMAND:
                   2300:                {
                   2301:                        char ** new_init_commands;
                   2302:                        char * new_command;
                   2303:                        /* when num_commands is 0, then realloc will be effectively a malloc call, internally */
1.1.1.2   misho    2304:                        /* Don't assign to conn->options->init_commands because in case of OOM we will lose the pointer and leak */
                   2305:                        new_init_commands = mnd_perealloc(conn->options->init_commands, sizeof(char *) * (conn->options->num_commands + 1), conn->persistent);
1.1       misho    2306:                        if (!new_init_commands) {
                   2307:                                goto oom;
                   2308:                        }
1.1.1.2   misho    2309:                        conn->options->init_commands = new_init_commands;
1.1       misho    2310:                        new_command = mnd_pestrdup(value, conn->persistent);
                   2311:                        if (!new_command) {
                   2312:                                goto oom;
                   2313:                        }
1.1.1.2   misho    2314:                        conn->options->init_commands[conn->options->num_commands] = new_command;
                   2315:                        ++conn->options->num_commands;
1.1       misho    2316:                        break;
                   2317:                }
                   2318:                case MYSQL_READ_DEFAULT_FILE:
                   2319:                case MYSQL_READ_DEFAULT_GROUP:
                   2320: #ifdef WHEN_SUPPORTED_BY_MYSQLI
                   2321:                case MYSQL_SET_CLIENT_IP:
                   2322:                case MYSQL_REPORT_DATA_TRUNCATION:
                   2323: #endif
                   2324:                        /* currently not supported. Todo!! */
                   2325:                        break;
                   2326:                case MYSQL_SET_CHARSET_NAME:
                   2327:                {
1.1.1.3   misho    2328:                        char * new_charset_name;
                   2329:                        if (!mysqlnd_find_charset_name(value)) {
                   2330:                                SET_CLIENT_ERROR(*conn->error_info, CR_CANT_FIND_CHARSET, UNKNOWN_SQLSTATE, "Unknown character set");
                   2331:                                ret = FAIL;
                   2332:                                break;
                   2333:                        }
                   2334:                                
                   2335:                        new_charset_name = mnd_pestrdup(value, conn->persistent);
1.1       misho    2336:                        if (!new_charset_name) {
                   2337:                                goto oom;
                   2338:                        }
1.1.1.2   misho    2339:                        if (conn->options->charset_name) {
                   2340:                                mnd_pefree(conn->options->charset_name, conn->persistent);
1.1       misho    2341:                        }
1.1.1.2   misho    2342:                        conn->options->charset_name = new_charset_name;
                   2343:                        DBG_INF_FMT("charset=%s", conn->options->charset_name);
1.1       misho    2344:                        break;
                   2345:                }
                   2346:                case MYSQL_OPT_NAMED_PIPE:
1.1.1.2   misho    2347:                        conn->options->protocol = MYSQL_PROTOCOL_PIPE;
1.1       misho    2348:                        break;
                   2349:                case MYSQL_OPT_PROTOCOL:
                   2350:                        if (*(unsigned int*) value < MYSQL_PROTOCOL_LAST) {
1.1.1.2   misho    2351:                                conn->options->protocol = *(unsigned int*) value;
1.1       misho    2352:                        }
                   2353:                        break;
                   2354: #ifdef WHEN_SUPPORTED_BY_MYSQLI
                   2355:                case MYSQL_SET_CHARSET_DIR:
                   2356:                case MYSQL_OPT_RECONNECT:
                   2357:                        /* we don't need external character sets, all character sets are
                   2358:                           compiled in. For compatibility we just ignore this setting.
                   2359:                           Same for protocol, we don't support old protocol */
                   2360:                case MYSQL_OPT_USE_REMOTE_CONNECTION:
                   2361:                case MYSQL_OPT_USE_EMBEDDED_CONNECTION:
                   2362:                case MYSQL_OPT_GUESS_CONNECTION:
                   2363:                        /* todo: throw an error, we don't support embedded */
                   2364:                        break;
                   2365: #endif
1.1.1.2   misho    2366:                case MYSQLND_OPT_MAX_ALLOWED_PACKET:
                   2367:                        if (*(unsigned int*) value > (1<<16)) {
                   2368:                                conn->options->max_allowed_packet = *(unsigned int*) value;
                   2369:                        }
                   2370:                        break;
                   2371:                case MYSQLND_OPT_AUTH_PROTOCOL:
                   2372:                {
                   2373:                        char * new_auth_protocol = value? mnd_pestrdup(value, conn->persistent) : NULL;
                   2374:                        if (value && !new_auth_protocol) {
                   2375:                                goto oom;
                   2376:                        }
                   2377:                        if (conn->options->auth_protocol) {
                   2378:                                mnd_pefree(conn->options->auth_protocol, conn->persistent);
                   2379:                        }
                   2380:                        conn->options->auth_protocol = new_auth_protocol;
                   2381:                        DBG_INF_FMT("auth_protocol=%s", conn->options->auth_protocol);
                   2382:                        break;
                   2383:                }
1.1.1.3   misho    2384:                case MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS:
                   2385:                        if (value && (*(unsigned int*) value) ? 1 : 0) {
                   2386:                                conn->options->flags |= CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS;
                   2387:                        } else {
                   2388:                                conn->options->flags &= ~CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS;
                   2389:                        }
                   2390:                        break;
1.1       misho    2391: #ifdef WHEN_SUPPORTED_BY_MYSQLI
                   2392:                case MYSQL_SHARED_MEMORY_BASE_NAME:
                   2393:                case MYSQL_OPT_USE_RESULT:
                   2394:                case MYSQL_SECURE_AUTH:
                   2395:                        /* not sure, todo ? */
                   2396: #endif
                   2397:                default:
                   2398:                        ret = FAIL;
                   2399:        }
1.1.1.2   misho    2400:        conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);  
1.1       misho    2401:        DBG_RETURN(ret);
                   2402: oom:
1.1.1.2   misho    2403:        SET_OOM_ERROR(*conn->error_info);
                   2404:        conn->m->local_tx_end(conn, this_func, FAIL TSRMLS_CC); 
                   2405: end:
1.1       misho    2406:        DBG_RETURN(FAIL);
                   2407: }
                   2408: /* }}} */
                   2409: 
                   2410: 
1.1.1.2   misho    2411: /* {{{ mysqlnd_conn_data::use_result */
1.1       misho    2412: static MYSQLND_RES *
1.1.1.2   misho    2413: MYSQLND_METHOD(mysqlnd_conn_data, use_result)(MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    2414: {
1.1.1.2   misho    2415:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, use_result);
                   2416:        MYSQLND_RES * result = NULL;
1.1       misho    2417: 
1.1.1.2   misho    2418:        DBG_ENTER("mysqlnd_conn_data::use_result");
1.1       misho    2419:        DBG_INF_FMT("conn=%llu", conn->thread_id);
                   2420: 
1.1.1.2   misho    2421:        if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   2422:                do {
                   2423:                        if (!conn->current_result) {
                   2424:                                break;
                   2425:                        }
1.1       misho    2426: 
1.1.1.2   misho    2427:                        /* Nothing to store for UPSERT/LOAD DATA */
                   2428:                        if (conn->last_query_type != QUERY_SELECT || CONN_GET_STATE(conn) != CONN_FETCHING_DATA) {
                   2429:                                SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
                   2430:                                DBG_ERR("Command out of sync");
                   2431:                                break;
                   2432:                        }
1.1       misho    2433: 
1.1.1.2   misho    2434:                        MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_UNBUFFERED_SETS);
1.1       misho    2435: 
1.1.1.2   misho    2436:                        conn->current_result->conn = conn->m->get_reference(conn TSRMLS_CC);
                   2437:                        result = conn->current_result->m.use_result(conn->current_result, FALSE TSRMLS_CC);
1.1       misho    2438: 
1.1.1.2   misho    2439:                        if (!result) {
                   2440:                                conn->current_result->m.free_result(conn->current_result, TRUE TSRMLS_CC);
                   2441:                        }
                   2442:                        conn->current_result = NULL;
                   2443:                } while (0);
                   2444: 
                   2445:                conn->m->local_tx_end(conn, this_func, result == NULL? FAIL:PASS TSRMLS_CC);    
1.1       misho    2446:        }
                   2447: 
                   2448:        DBG_RETURN(result);
                   2449: }
                   2450: /* }}} */
                   2451: 
                   2452: 
1.1.1.2   misho    2453: /* {{{ mysqlnd_conn_data::store_result */
1.1       misho    2454: static MYSQLND_RES *
1.1.1.2   misho    2455: MYSQLND_METHOD(mysqlnd_conn_data, store_result)(MYSQLND_CONN_DATA * const conn TSRMLS_DC)
1.1       misho    2456: {
1.1.1.2   misho    2457:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, store_result);
                   2458:        MYSQLND_RES * result = NULL;
1.1       misho    2459: 
1.1.1.2   misho    2460:        DBG_ENTER("mysqlnd_conn_data::store_result");
1.1       misho    2461:        DBG_INF_FMT("conn=%llu", conn->thread_id);
                   2462: 
1.1.1.2   misho    2463:        if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   2464:                do {
                   2465:                        if (!conn->current_result) {
                   2466:                                break;
                   2467:                        }
1.1       misho    2468: 
1.1.1.2   misho    2469:                        /* Nothing to store for UPSERT/LOAD DATA*/
                   2470:                        if (conn->last_query_type != QUERY_SELECT || CONN_GET_STATE(conn) != CONN_FETCHING_DATA) {
                   2471:                                SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
                   2472:                                DBG_ERR("Command out of sync");
                   2473:                                break;
                   2474:                        }
1.1       misho    2475: 
1.1.1.2   misho    2476:                        MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_BUFFERED_SETS);
1.1       misho    2477: 
1.1.1.2   misho    2478:                        result = conn->current_result->m.store_result(conn->current_result, conn, FALSE TSRMLS_CC);
                   2479:                        if (!result) {
                   2480:                                conn->current_result->m.free_result(conn->current_result, TRUE TSRMLS_CC);
                   2481:                        }
                   2482:                        conn->current_result = NULL;
                   2483:                } while (0);
                   2484: 
                   2485:                conn->m->local_tx_end(conn, this_func, result == NULL? FAIL:PASS TSRMLS_CC);    
1.1       misho    2486:        }
                   2487:        DBG_RETURN(result);
                   2488: }
                   2489: /* }}} */
                   2490: 
                   2491: 
1.1.1.2   misho    2492: /* {{{ mysqlnd_conn_data::get_connection_stats */
1.1       misho    2493: static void
1.1.1.2   misho    2494: MYSQLND_METHOD(mysqlnd_conn_data, get_connection_stats)(const MYSQLND_CONN_DATA * const conn,
                   2495:                                                                                                   zval * return_value TSRMLS_DC ZEND_FILE_LINE_DC)
1.1       misho    2496: {
1.1.1.2   misho    2497:        DBG_ENTER("mysqlnd_conn_data::get_connection_stats");
1.1       misho    2498:        mysqlnd_fill_stats_hash(conn->stats, mysqlnd_stats_values_names, return_value TSRMLS_CC ZEND_FILE_LINE_CC);
                   2499:        DBG_VOID_RETURN;
                   2500: }
                   2501: /* }}} */
                   2502: 
                   2503: 
1.1.1.2   misho    2504: /* {{{ mysqlnd_conn_data::set_autocommit */
1.1       misho    2505: static enum_func_status
1.1.1.2   misho    2506: MYSQLND_METHOD(mysqlnd_conn_data, set_autocommit)(MYSQLND_CONN_DATA * conn, unsigned int mode TSRMLS_DC)
1.1       misho    2507: {
1.1.1.2   misho    2508:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, set_autocommit);
                   2509:        enum_func_status ret = FAIL;
                   2510:        DBG_ENTER("mysqlnd_conn_data::set_autocommit");
                   2511: 
                   2512:        if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   2513:                ret = conn->m->query(conn, (mode) ? "SET AUTOCOMMIT=1":"SET AUTOCOMMIT=0", sizeof("SET AUTOCOMMIT=1") - 1 TSRMLS_CC);
                   2514:                conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);  
                   2515:        }
                   2516: 
1.1       misho    2517:        DBG_RETURN(ret);
                   2518: }
                   2519: /* }}} */
                   2520: 
                   2521: 
1.1.1.2   misho    2522: /* {{{ mysqlnd_conn_data::tx_commit */
1.1       misho    2523: static enum_func_status
1.1.1.2   misho    2524: MYSQLND_METHOD(mysqlnd_conn_data, tx_commit)(MYSQLND_CONN_DATA * conn TSRMLS_DC)
1.1       misho    2525: {
1.1.1.2   misho    2526:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, tx_commit);
                   2527:        enum_func_status ret = FAIL;
                   2528:        DBG_ENTER("mysqlnd_conn_data::tx_commit");
                   2529: 
                   2530:        if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   2531:                ret = conn->m->query(conn, "COMMIT", sizeof("COMMIT") - 1 TSRMLS_CC);
                   2532:                conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);  
                   2533:        }
                   2534: 
1.1       misho    2535:        DBG_RETURN(ret);
                   2536: }
                   2537: /* }}} */
                   2538: 
                   2539: 
1.1.1.2   misho    2540: /* {{{ mysqlnd_conn_data::tx_rollback */
1.1       misho    2541: static enum_func_status
1.1.1.2   misho    2542: MYSQLND_METHOD(mysqlnd_conn_data, tx_rollback)(MYSQLND_CONN_DATA * conn TSRMLS_DC)
1.1       misho    2543: {
1.1.1.2   misho    2544:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, tx_rollback);
                   2545:        enum_func_status ret = FAIL;
                   2546:        DBG_ENTER("mysqlnd_conn_data::tx_rollback");
                   2547: 
                   2548:        if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   2549:                ret = conn->m->query(conn, "ROLLBACK", sizeof("ROLLBACK") - 1 TSRMLS_CC);
                   2550:                conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);  
                   2551:        }
                   2552: 
1.1       misho    2553:        DBG_RETURN(ret);
                   2554: }
                   2555: /* }}} */
                   2556: 
                   2557: 
1.1.1.2   misho    2558: /* {{{ mysqlnd_conn_data::local_tx_start */
                   2559: static enum_func_status
                   2560: MYSQLND_METHOD(mysqlnd_conn_data, local_tx_start)(MYSQLND_CONN_DATA * conn, size_t this_func TSRMLS_DC)
                   2561: {
                   2562:        enum_func_status ret = PASS;
                   2563:        DBG_ENTER("mysqlnd_conn_data::local_tx_start");
                   2564:        DBG_RETURN(ret);
                   2565: }
                   2566: /* }}} */
1.1       misho    2567: 
                   2568: 
1.1.1.2   misho    2569: /* {{{ mysqlnd_conn_data::local_tx_end */
                   2570: static enum_func_status
                   2571: MYSQLND_METHOD(mysqlnd_conn_data, local_tx_end)(MYSQLND_CONN_DATA * conn, size_t this_func, enum_func_status status TSRMLS_DC)
                   2572: {
                   2573:        DBG_ENTER("mysqlnd_conn_data::local_tx_end");
                   2574:        DBG_RETURN(status);
                   2575: }
                   2576: /* }}} */
1.1       misho    2577: 
                   2578: 
1.1.1.2   misho    2579: /* {{{ mysqlnd_conn_data::init */
1.1       misho    2580: static enum_func_status
1.1.1.2   misho    2581: MYSQLND_METHOD(mysqlnd_conn_data, init)(MYSQLND_CONN_DATA * conn TSRMLS_DC)
1.1       misho    2582: {
1.1.1.2   misho    2583:        DBG_ENTER("mysqlnd_conn_data::init");
1.1       misho    2584:        mysqlnd_stats_init(&conn->stats, STAT_LAST);
                   2585:        SET_ERROR_AFF_ROWS(conn);
                   2586: 
1.1.1.2   misho    2587:        conn->net = mysqlnd_net_init(conn->persistent, conn->stats, conn->error_info TSRMLS_CC);
1.1       misho    2588:        conn->protocol = mysqlnd_protocol_init(conn->persistent TSRMLS_CC);
                   2589: 
1.1.1.2   misho    2590:        DBG_RETURN(conn->stats && conn->net && conn->protocol? PASS:FAIL);
1.1       misho    2591: }
                   2592: /* }}} */
                   2593: 
                   2594: 
1.1.1.2   misho    2595: MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND_CONN_DATA * const conn TSRMLS_DC);
1.1       misho    2596: 
                   2597: 
1.1.1.2   misho    2598: MYSQLND_CLASS_METHODS_START(mysqlnd_conn_data)
                   2599:        MYSQLND_METHOD(mysqlnd_conn_data, init),
                   2600:        MYSQLND_METHOD(mysqlnd_conn_data, connect),
1.1       misho    2601: 
1.1.1.2   misho    2602:        MYSQLND_METHOD(mysqlnd_conn_data, escape_string),
                   2603:        MYSQLND_METHOD(mysqlnd_conn_data, set_charset),
                   2604:        MYSQLND_METHOD(mysqlnd_conn_data, query),
                   2605:        MYSQLND_METHOD(mysqlnd_conn_data, send_query),
                   2606:        MYSQLND_METHOD(mysqlnd_conn_data, reap_query),
                   2607:        MYSQLND_METHOD(mysqlnd_conn_data, use_result),
                   2608:        MYSQLND_METHOD(mysqlnd_conn_data, store_result),
                   2609:        MYSQLND_METHOD(mysqlnd_conn_data, next_result),
                   2610:        MYSQLND_METHOD(mysqlnd_conn_data, more_results),
1.1       misho    2611: 
1.1.1.2   misho    2612:        _mysqlnd_stmt_init,
1.1       misho    2613: 
1.1.1.2   misho    2614:        MYSQLND_METHOD(mysqlnd_conn_data, shutdown),
                   2615:        MYSQLND_METHOD(mysqlnd_conn_data, refresh),
1.1       misho    2616: 
1.1.1.2   misho    2617:        MYSQLND_METHOD(mysqlnd_conn_data, ping),
                   2618:        MYSQLND_METHOD(mysqlnd_conn_data, kill),
                   2619:        MYSQLND_METHOD(mysqlnd_conn_data, select_db),
                   2620:        MYSQLND_METHOD(mysqlnd_conn_data, dump_debug_info),
                   2621:        MYSQLND_METHOD(mysqlnd_conn_data, change_user),
                   2622: 
                   2623:        MYSQLND_METHOD(mysqlnd_conn_data, errno),
                   2624:        MYSQLND_METHOD(mysqlnd_conn_data, error),
                   2625:        MYSQLND_METHOD(mysqlnd_conn_data, sqlstate),
                   2626:        MYSQLND_METHOD(mysqlnd_conn_data, thread_id),
                   2627: 
                   2628:        MYSQLND_METHOD(mysqlnd_conn_data, get_connection_stats),
                   2629: 
                   2630:        MYSQLND_METHOD(mysqlnd_conn_data, get_server_version),
                   2631:        MYSQLND_METHOD(mysqlnd_conn_data, get_server_info),
                   2632:        MYSQLND_METHOD(mysqlnd_conn_data, statistic),
                   2633:        MYSQLND_METHOD(mysqlnd_conn_data, get_host_info),
                   2634:        MYSQLND_METHOD(mysqlnd_conn_data, get_proto_info),
                   2635:        MYSQLND_METHOD(mysqlnd_conn_data, info),
                   2636:        MYSQLND_METHOD(mysqlnd_conn_data, charset_name),
                   2637:        MYSQLND_METHOD(mysqlnd_conn_data, list_fields),
                   2638:        MYSQLND_METHOD(mysqlnd_conn_data, list_method),
                   2639: 
                   2640:        MYSQLND_METHOD(mysqlnd_conn_data, insert_id),
                   2641:        MYSQLND_METHOD(mysqlnd_conn_data, affected_rows),
                   2642:        MYSQLND_METHOD(mysqlnd_conn_data, warning_count),
                   2643:        MYSQLND_METHOD(mysqlnd_conn_data, field_count),
                   2644: 
                   2645:        MYSQLND_METHOD(mysqlnd_conn_data, server_status),
                   2646: 
                   2647:        MYSQLND_METHOD(mysqlnd_conn_data, set_server_option),
                   2648:        MYSQLND_METHOD(mysqlnd_conn_data, set_client_option),
                   2649:        MYSQLND_METHOD(mysqlnd_conn_data, free_contents),
                   2650:        MYSQLND_METHOD(mysqlnd_conn_data, free_options),
                   2651: 
                   2652:        MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, dtor),
1.1       misho    2653: 
1.1.1.2   misho    2654:        mysqlnd_query_read_result_set_header,
                   2655: 
                   2656:        MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, get_reference),
                   2657:        MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, free_reference),
                   2658:        MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, get_state),
                   2659:        MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, set_state),
                   2660: 
                   2661:        MYSQLND_METHOD(mysqlnd_conn_data, simple_command),
                   2662:        MYSQLND_METHOD(mysqlnd_conn_data, simple_command_handle_response),
                   2663:        MYSQLND_METHOD(mysqlnd_conn_data, restart_psession),
                   2664:        MYSQLND_METHOD(mysqlnd_conn_data, end_psession),
                   2665:        MYSQLND_METHOD(mysqlnd_conn_data, send_close),
                   2666: 
                   2667:        MYSQLND_METHOD(mysqlnd_conn_data, ssl_set),
                   2668:        mysqlnd_result_init,
                   2669:        MYSQLND_METHOD(mysqlnd_conn_data, set_autocommit),
                   2670:        MYSQLND_METHOD(mysqlnd_conn_data, tx_commit),
                   2671:        MYSQLND_METHOD(mysqlnd_conn_data, tx_rollback),
                   2672:        MYSQLND_METHOD(mysqlnd_conn_data, local_tx_start),
                   2673:        MYSQLND_METHOD(mysqlnd_conn_data, local_tx_end)
                   2674: MYSQLND_CLASS_METHODS_END;
                   2675: 
                   2676: 
                   2677: /* {{{ mysqlnd_conn::get_reference */
                   2678: static MYSQLND *
                   2679: MYSQLND_METHOD(mysqlnd_conn, clone_object)(MYSQLND * const conn TSRMLS_DC)
1.1       misho    2680: {
1.1.1.2   misho    2681:        MYSQLND * ret;
                   2682:        DBG_ENTER("mysqlnd_conn::get_reference");
                   2683:        ret = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory).clone_connection_object(conn TSRMLS_CC);
                   2684:        DBG_RETURN(ret);
1.1       misho    2685: }
                   2686: /* }}} */
                   2687: 
1.1.1.2   misho    2688: 
                   2689: /* {{{ mysqlnd_conn_data::dtor */
                   2690: static void
                   2691: MYSQLND_METHOD_PRIVATE(mysqlnd_conn, dtor)(MYSQLND * conn TSRMLS_DC)
1.1       misho    2692: {
1.1.1.2   misho    2693:        DBG_ENTER("mysqlnd_conn::dtor");
                   2694:        DBG_INF_FMT("conn=%llu", conn->data->thread_id);
1.1       misho    2695: 
1.1.1.2   misho    2696:        conn->data->m->free_reference(conn->data TSRMLS_CC);
1.1       misho    2697: 
1.1.1.2   misho    2698:        mnd_pefree(conn, conn->persistent);
1.1       misho    2699: 
1.1.1.2   misho    2700:        DBG_VOID_RETURN;
1.1       misho    2701: }
                   2702: /* }}} */
                   2703: 
                   2704: 
1.1.1.2   misho    2705: /* {{{ mysqlnd_conn_data::close */
                   2706: static enum_func_status
                   2707: MYSQLND_METHOD(mysqlnd_conn, close)(MYSQLND * conn_handle, enum_connection_close_type close_type TSRMLS_DC)
1.1       misho    2708: {
1.1.1.2   misho    2709:        size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_methods, close);
                   2710:        MYSQLND_CONN_DATA * conn = conn_handle->data;
                   2711:        enum_func_status ret = FAIL;
                   2712: 
                   2713:        DBG_ENTER("mysqlnd_conn::close");
                   2714:        DBG_INF_FMT("conn=%llu", conn->thread_id);
                   2715: 
                   2716:        if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
                   2717:                if (CONN_GET_STATE(conn) >= CONN_READY) {
                   2718:                        static enum_mysqlnd_collected_stats close_type_to_stat_map[MYSQLND_CLOSE_LAST] = {
                   2719:                                STAT_CLOSE_EXPLICIT,
                   2720:                                STAT_CLOSE_IMPLICIT,
                   2721:                                STAT_CLOSE_DISCONNECT
                   2722:                        };
                   2723:                        MYSQLND_INC_CONN_STATISTIC(conn->stats, close_type_to_stat_map[close_type]);
                   2724:                }
                   2725: 
                   2726:                /*
                   2727:                  Close now, free_reference will try,
                   2728:                  if we are last, but that's not a problem.
                   2729:                */
                   2730:                ret = conn->m->send_close(conn TSRMLS_CC);
                   2731: 
                   2732:                /* do it after free_reference/dtor and we might crash */
                   2733:                conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);
                   2734: 
                   2735:                conn_handle->m->dtor(conn_handle TSRMLS_CC);
                   2736:        }
                   2737:        DBG_RETURN(ret);
1.1       misho    2738: }
                   2739: /* }}} */
                   2740: 
                   2741: 
1.1.1.2   misho    2742: MYSQLND_CLASS_METHODS_START(mysqlnd_conn)
                   2743:        MYSQLND_METHOD(mysqlnd_conn, connect),
                   2744:        MYSQLND_METHOD(mysqlnd_conn, clone_object),
                   2745:        MYSQLND_METHOD_PRIVATE(mysqlnd_conn, dtor),
                   2746:        MYSQLND_METHOD(mysqlnd_conn, close)
                   2747: MYSQLND_CLASS_METHODS_END;
                   2748: 
                   2749: 
                   2750: /* {{{ _mysqlnd_init */
                   2751: PHPAPI MYSQLND *
                   2752: _mysqlnd_init(zend_bool persistent TSRMLS_DC)
1.1       misho    2753: {
1.1.1.2   misho    2754:        MYSQLND * ret;
                   2755:        DBG_ENTER("mysqlnd_init");
                   2756:        ret = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory).get_connection(persistent TSRMLS_CC);
                   2757:        DBG_RETURN(ret);
1.1       misho    2758: }
                   2759: /* }}} */
                   2760: 
                   2761: /*
                   2762:  * Local variables:
                   2763:  * tab-width: 4
                   2764:  * c-basic-offset: 4
                   2765:  * End:
                   2766:  * vim600: noet sw=4 ts=4 fdm=marker
                   2767:  * vim<600: noet sw=4 ts=4
                   2768:  */

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