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

LTP GCOV extension - code coverage report
Current view: directory - mysqlnd - mysqlnd.c
Test: PHP Code Coverage
Date: 2009-11-23 Instrumented lines: 959
Code covered: 81.0 % Executed lines: 777
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Mon, 23 Nov 2009 17:39:32 +0000 (34 hours ago)

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