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

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

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