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

Generated by: LTP GCOV extension version 1.5

Generated at Sat, 21 Nov 2009 12:27:03 +0000 (3 days ago)

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