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

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

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