PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/mysqlnd - mysqlnd.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 839 1036 81.0 %
Date: 2014-07-13 Functions: 66 73 90.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sun, 13 Jul 2014 23:57:52 +0000 (9 days ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.