summaryrefslogtreecommitdiff
path: root/ext/mysqlnd/mysqlnd.c
diff options
context:
space:
mode:
authorAndrey Hristov <andrey@php.net>2007-10-02 10:45:27 +0000
committerAndrey Hristov <andrey@php.net>2007-10-02 10:45:27 +0000
commit9ac92cfecb9522d4679d7e3dc2e38be1b11a6467 (patch)
treee7e5931f5d0359b749c0a4668658bd2b2efe2cea /ext/mysqlnd/mysqlnd.c
parentf0e5df4544d0aa7378bc620577ba1e814a1a0aea (diff)
downloadphp-git-9ac92cfecb9522d4679d7e3dc2e38be1b11a6467.tar.gz
Update mysqlnd in HEAD
Updated ext/mysql and ext/mysqli in HEAD
Diffstat (limited to 'ext/mysqlnd/mysqlnd.c')
-rw-r--r--ext/mysqlnd/mysqlnd.c670
1 files changed, 513 insertions, 157 deletions
diff --git a/ext/mysqlnd/mysqlnd.c b/ext/mysqlnd/mysqlnd.c
index 78ac992ebb..98b3ab7dc9 100644
--- a/ext/mysqlnd/mysqlnd.c
+++ b/ext/mysqlnd/mysqlnd.c
@@ -19,7 +19,6 @@
*/
/* $Id$ */
-
#include "php.h"
#include "mysqlnd.h"
#include "mysqlnd_wireprotocol.h"
@@ -27,13 +26,12 @@
#include "mysqlnd_result.h"
#include "mysqlnd_statistics.h"
#include "mysqlnd_charset.h"
+#include "mysqlnd_debug.h"
#include "php_ini.h"
#include "ext/standard/basic_functions.h"
#include "ext/standard/php_lcg.h"
#include "ext/standard/info.h"
-#define MYSQLND_SILENT
-
/* the server doesn't support 4byte utf8, but let's make it forward compatible */
#define MYSQLND_MAX_ALLOWED_USER_LEN 256 /* 64 char * 4byte */
#define MYSQLND_MAX_ALLOWED_DB_LEN 256 /* 64 char * 4byte */
@@ -62,26 +60,27 @@ extern MYSQLND_CHARSET *mysqlnd_charsets;
-static const char * mysqlnd_server_gone = "MySQL server has gone away";
+const char * mysqlnd_server_gone = "MySQL server has gone away";
const char * mysqlnd_out_of_sync = "Commands out of sync; you can't run this command now";
MYSQLND_STATS *mysqlnd_global_stats = NULL;
static zend_bool mysqlnd_library_initted = FALSE;
+
+enum_func_status mysqlnd_send_close(MYSQLND * conn TSRMLS_DC);
+
/* {{{ mysqlnd_library_init */
static
-void mysqlnd_library_init(zend_bool collect_statistics)
+void mysqlnd_library_init()
{
if (mysqlnd_library_initted == FALSE) {
mysqlnd_library_initted = TRUE;
_mysqlnd_init_ps_subsystem();
- if (collect_statistics) {
- mysqlnd_global_stats = calloc(1, sizeof(MYSQLND_STATS));
-
+ /* Should be calloc, as mnd_calloc will reference LOCK_access*/
+ mysqlnd_global_stats = calloc(1, sizeof(MYSQLND_STATS));
#ifdef ZTS
- mysqlnd_global_stats->LOCK_access = tsrm_mutex_alloc();
+ mysqlnd_global_stats->LOCK_access = tsrm_mutex_alloc();
#endif
- }
}
}
/* }}} */
@@ -92,13 +91,12 @@ static
void mysqlnd_library_end()
{
if (mysqlnd_library_initted == TRUE) {
- if (mysqlnd_global_stats) {
#ifdef ZTS
- tsrm_mutex_free(mysqlnd_global_stats->LOCK_access);
+ tsrm_mutex_free(mysqlnd_global_stats->LOCK_access);
#endif
- free(mysqlnd_global_stats);
- mysqlnd_global_stats = NULL;
- }
+ /* mnd_free will reference LOCK_access and crash...*/
+ free(mysqlnd_global_stats);
+ mysqlnd_global_stats = NULL;
mysqlnd_library_initted = FALSE;
}
}
@@ -111,106 +109,130 @@ MYSQLND_METHOD(mysqlnd_conn, free_contents)(MYSQLND *conn TSRMLS_DC)
{
zend_bool pers = conn->persistent;
- mysqlnd_local_infile_default(conn, TRUE);
+ DBG_ENTER("mysqlnd_conn::free_contents");
+
+ mysqlnd_local_infile_default(conn);
if (conn->current_result) {
conn->current_result->m.free_result_contents(conn->current_result TSRMLS_CC);
- efree(conn->current_result);
+ mnd_efree(conn->current_result);
conn->current_result = NULL;
}
if (conn->net.stream) {
- php_stream_free(conn->net.stream, (pers) ? PHP_STREAM_FREE_RSRC_DTOR :
- PHP_STREAM_FREE_CLOSE);
+ DBG_INF_FMT("Freeing stream. abstract=%p", conn->net.stream->abstract);
+ if (pers) {
+ php_stream_free(conn->net.stream, PHP_STREAM_FREE_CLOSE_PERSISTENT | PHP_STREAM_FREE_RSRC_DTOR);
+ } else {
+ php_stream_free(conn->net.stream, PHP_STREAM_FREE_CLOSE);
+
+ }
conn->net.stream = NULL;
}
+
+ DBG_INF("Freeing memory of members");
if (conn->host) {
- pefree(conn->host, pers);
+ DBG_INF("Freeing host");
+ mnd_pefree(conn->host, pers);
conn->host = NULL;
}
if (conn->user) {
- pefree(conn->user, pers);
+ DBG_INF("Freeing user");
+ mnd_pefree(conn->user, pers);
conn->user = NULL;
}
if (conn->passwd) {
- pefree(conn->passwd, pers);
+ DBG_INF("Freeing passwd");
+ mnd_pefree(conn->passwd, pers);
conn->passwd = NULL;
}
if (conn->unix_socket) {
- pefree(conn->unix_socket, pers);
+ DBG_INF("Freeing unix_socket");
+ mnd_pefree(conn->unix_socket, pers);
conn->unix_socket = NULL;
}
if (conn->scheme) {
- pefree(conn->scheme, pers);
+ DBG_INF("Freeing scheme");
+ mnd_pefree(conn->scheme, pers);
conn->scheme = NULL;
}
if (conn->server_version) {
- pefree(conn->server_version, pers);
+ DBG_INF("Freeing server_version");
+ mnd_pefree(conn->server_version, pers);
conn->server_version = NULL;
}
if (conn->host_info) {
- pefree(conn->host_info, pers);
+ DBG_INF("Freeing host_info");
+ mnd_pefree(conn->host_info, pers);
conn->host_info = NULL;
}
if (conn->scramble) {
- pefree(conn->scramble, pers);
+ DBG_INF("Freeing scramble");
+ mnd_pefree(conn->scramble, pers);
conn->scramble = NULL;
}
if (conn->last_message) {
- pefree(conn->last_message, pers);
+ mnd_pefree(conn->last_message, pers);
conn->last_message = NULL;
}
if (conn->options.charset_name) {
- pefree(conn->options.charset_name, pers);
+ mnd_pefree(conn->options.charset_name, pers);
conn->options.charset_name = NULL;
}
if (conn->options.num_commands) {
unsigned int i;
for (i=0; i < conn->options.num_commands; i++) {
- pefree(conn->options.init_commands[i], pers);
+ mnd_pefree(conn->options.init_commands[i], pers);
}
- pefree(conn->options.init_commands, pers);
+ mnd_pefree(conn->options.init_commands, pers);
conn->options.init_commands = NULL;
}
if (conn->options.cfg_file) {
- pefree(conn->options.cfg_file, pers);
+ mnd_pefree(conn->options.cfg_file, pers);
conn->options.cfg_file = NULL;
}
if (conn->options.cfg_section) {
- pefree(conn->options.cfg_section, pers);
+ mnd_pefree(conn->options.cfg_section, pers);
conn->options.cfg_section = NULL;
}
if (conn->options.ssl_key) {
- pefree(conn->options.ssl_key, pers);
+ mnd_pefree(conn->options.ssl_key, pers);
conn->options.ssl_key = NULL;
}
if (conn->options.ssl_cert) {
- pefree(conn->options.ssl_cert, pers);
+ mnd_pefree(conn->options.ssl_cert, pers);
conn->options.ssl_cert = NULL;
}
if (conn->options.ssl_ca) {
- pefree(conn->options.ssl_ca, pers);
+ mnd_pefree(conn->options.ssl_ca, pers);
conn->options.ssl_ca = NULL;
}
if (conn->options.ssl_capath) {
- pefree(conn->options.ssl_capath, pers);
+ mnd_pefree(conn->options.ssl_capath, pers);
conn->options.ssl_capath = NULL;
}
if (conn->options.ssl_cipher) {
- pefree(conn->options.ssl_cipher, pers);
+ mnd_pefree(conn->options.ssl_cipher, pers);
conn->options.ssl_cipher = NULL;
}
if (conn->zval_cache) {
+ DBG_INF("Freeing zval cache reference");
mysqlnd_palloc_free_thd_cache_reference(&conn->zval_cache);
conn->zval_cache = NULL;
}
if (conn->qcache) {
+ DBG_INF("Freeing qcache reference");
mysqlnd_qcache_free_cache_reference(&conn->qcache);
conn->qcache = NULL;
}
if (conn->net.cmd_buffer.buffer) {
- pefree(conn->net.cmd_buffer.buffer, pers);
+ DBG_INF("Freeing cmd buffer");
+ mnd_pefree(conn->net.cmd_buffer.buffer, pers);
conn->net.cmd_buffer.buffer = NULL;
}
+ conn->charset = NULL;
+ conn->greet_charset = NULL;
+
+ DBG_VOID_RETURN;
}
/* }}} */
@@ -219,9 +241,14 @@ MYSQLND_METHOD(mysqlnd_conn, free_contents)(MYSQLND *conn TSRMLS_DC)
static void
MYSQLND_METHOD_PRIVATE(mysqlnd_conn, dtor)(MYSQLND *conn TSRMLS_DC)
{
+ DBG_ENTER("mysqlnd_conn::dtor");
+ DBG_INF_FMT("conn=%llu", conn->thread_id);
+
conn->m->free_contents(conn TSRMLS_CC);
- pefree(conn, conn->persistent);
+ mnd_pefree(conn, conn->persistent);
+
+ DBG_VOID_RETURN;
}
/* }}} */
@@ -233,19 +260,22 @@ mysqlnd_simple_command_handle_response(MYSQLND *conn, enum php_mysql_packet_type
TSRMLS_DC)
{
enum_func_status ret;
+
+ DBG_ENTER("mysqlnd_simple_command_handle_response");
+ DBG_INF_FMT("silent=%d packet=%d command=%s", silent, ok_packet, mysqlnd_command_to_text[command]);
+
switch (ok_packet) {
case PROT_OK_PACKET:{
php_mysql_packet_ok ok_response;
PACKET_INIT_ALLOCA(ok_response, PROT_OK_PACKET);
if (FAIL == (ret = PACKET_READ_ALLOCA(ok_response, conn))) {
if (!silent) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading %s's OK packet",
- mysqlnd_command_to_text[command]);
+ DBG_ERR_FMT("Error while reading %s's OK packet", mysqlnd_command_to_text[command]);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading %s's OK packet. PID=%d",
+ mysqlnd_command_to_text[command], getpid());
}
} else {
-#ifndef MYSQLND_SILENT
- php_printf("\tOK from server\n");
-#endif
+ DBG_INF_FMT("OK from server");
if (0xFF == ok_response.field_count) {
/* The server signalled error. Set the error */
SET_CLIENT_ERROR(conn->error_info, ok_response.error_no,
@@ -283,8 +313,9 @@ mysqlnd_simple_command_handle_response(MYSQLND *conn, enum php_mysql_packet_type
SET_CLIENT_ERROR(conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE,
"Malformed packet");
if (!silent) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading %s's EOF packet",
- mysqlnd_command_to_text[command]);
+ DBG_ERR_FMT("Error while reading %s's EOF packet", mysqlnd_command_to_text[command]);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading %s's EOF packet. PID=%d",
+ mysqlnd_command_to_text[command], getpid());
}
} else if (0xFF == ok_response.field_count) {
/* The server signalled error. Set the error */
@@ -295,14 +326,13 @@ mysqlnd_simple_command_handle_response(MYSQLND *conn, enum php_mysql_packet_type
SET_CLIENT_ERROR(conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE,
"Malformed packet");
if (!silent) {
+ DBG_ERR_FMT("EOF packet expected, field count wasn't 0xFE but 0x%2X", ok_response.field_count);
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"EOF packet expected, field count wasn't 0xFE but 0x%2X",
ok_response.field_count);
}
} else {
-#ifndef MYSQLND_SILENT
- php_printf("\tOK from server\n");
-#endif
+ DBG_INF_FMT("OK from server");
}
PACKET_FREE_ALLOCA(ok_response);
break;
@@ -315,7 +345,8 @@ mysqlnd_simple_command_handle_response(MYSQLND *conn, enum php_mysql_packet_type
ok_packet);
break;
}
- return ret;
+ DBG_INF(ret == PASS ? "PASS":"FAIL");
+ DBG_RETURN(ret);
}
/* }}} */
@@ -329,16 +360,21 @@ mysqlnd_simple_command(MYSQLND *conn, enum php_mysqlnd_server_command command,
enum_func_status ret = PASS;
php_mysql_packet_command cmd_packet;
+ DBG_ENTER("mysqlnd_simple_command");
+ DBG_INF_FMT("command=%s ok_packet=%d silent=%d", mysqlnd_command_to_text[command], ok_packet, silent);
+
switch (conn->state) {
case CONN_READY:
break;
case CONN_QUIT_SENT:
SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
- return FAIL;
+ DBG_ERR("Server is gone");
+ DBG_RETURN(FAIL);
default:
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
mysqlnd_out_of_sync);
- return FAIL;
+ DBG_ERR("Command out of sync");
+ DBG_RETURN(FAIL);
}
/* clean UPSERT info */
@@ -355,9 +391,10 @@ mysqlnd_simple_command(MYSQLND *conn, enum php_mysqlnd_server_command command,
if (! PACKET_WRITE_ALLOCA(cmd_packet, conn)) {
if (!silent) {
- php_error(E_WARNING, "Error while sending %s packet", mysqlnd_command_to_text[command]);
+ DBG_ERR_FMT("Error while sending %s packet", mysqlnd_command_to_text[command]);
+ php_error(E_WARNING, "Error while sending %s packet. PID=%d", mysqlnd_command_to_text[command], getpid());
}
- SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
+ DBG_ERR("Server is gone");
ret = FAIL;
} else if (ok_packet != PROT_LAST) {
ret = mysqlnd_simple_command_handle_response(conn, ok_packet, silent, command TSRMLS_CC);
@@ -369,7 +406,8 @@ mysqlnd_simple_command(MYSQLND *conn, enum php_mysqlnd_server_command command,
to us. We should not free it.
*/
- return ret;
+ DBG_INF(ret == PASS ? "PASS":"FAIL");
+ DBG_RETURN(ret);
}
/* }}} */
@@ -379,23 +417,29 @@ static enum_func_status
MYSQLND_METHOD(mysqlnd_conn, set_server_option)(MYSQLND * const conn,
enum_mysqlnd_server_option option TSRMLS_DC)
{
+ enum_func_status ret;
char buffer[2];
+ DBG_ENTER("mysqlnd_conn::set_server_option");
+
int2store(buffer, (uint) option);
- return mysqlnd_simple_command(conn, COM_SET_OPTION, buffer, sizeof(buffer),
- PROT_EOF_PACKET, FALSE TSRMLS_CC);
+ ret = mysqlnd_simple_command(conn, COM_SET_OPTION, buffer, sizeof(buffer),
+ PROT_EOF_PACKET, FALSE TSRMLS_CC);
+ DBG_RETURN(ret);
}
/* }}} */
-/* {{{ mysqlnd_start_psession */
-PHPAPI void mysqlnd_restart_psession(MYSQLND *conn)
+/* {{{ _mysqlnd_restart_psession */
+PHPAPI void _mysqlnd_restart_psession(MYSQLND *conn TSRMLS_DC)
{
+ DBG_ENTER("_mysqlnd_restart_psession");
MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_CONNECT_REUSED);
/* Free here what should not be seen by the next script */
if (conn->last_message) {
- pefree(conn->last_message, conn->persistent);
+ mnd_pefree(conn->last_message, conn->persistent);
conn->last_message = NULL;
}
+ DBG_VOID_RETURN;
}
/* }}} */
@@ -421,22 +465,40 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
{
char *transport = NULL, *errstr = NULL;
char *hashed_details = NULL;
- int transport_len, errcode = 0;
+ int transport_len, hashed_details_len, errcode = 0;
unsigned int streams_options = ENFORCE_SAFE_MODE;
unsigned int streams_flags = STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT;
zend_bool self_alloced = FALSE;
struct timeval tv;
zend_bool unix_socket = FALSE;
const MYSQLND_CHARSET * charset;
+ zend_bool reconnect = FALSE;
php_mysql_packet_greet greet_packet;
php_mysql_packet_auth *auth_packet;
php_mysql_packet_ok ok_packet;
- if (conn && conn->state != CONN_ALLOCED) {
- SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
- mysqlnd_out_of_sync);
- return NULL;
+ DBG_ENTER("mysqlnd_connect");
+ DBG_INF_FMT("host=%s user=%s db=%s port=%d flags=%d persistent=%d state=%d",
+ host?host:"", user?user:"", db?db:"", port, mysql_flags,
+ conn? conn->persistent:0, conn? conn->state:-1);
+
+ DBG_INF_FMT("state=%d", conn->state);
+ if (conn && conn->state > CONN_ALLOCED && conn->state ) {
+ DBG_INF("Connecting on a connected handle.");
+
+ if (conn->state < CONN_QUIT_SENT) {
+ MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_CLOSE_IMPLICIT);
+ reconnect = TRUE;
+ mysqlnd_send_close(conn TSRMLS_CC);
+ }
+
+ conn->m->free_contents(conn TSRMLS_CC);
+ MYSQLND_DEC_CONN_STATISTIC(&conn->stats, STAT_OPENED_CONNECTIONS);
+ if (conn->persistent) {
+ MYSQLND_DEC_CONN_STATISTIC(&conn->stats, STAT_OPENED_PERSISTENT_CONNECTIONS);
+ }
+ /* Now reconnect using the same handle */
}
if (!host || !host[0]) {
@@ -468,14 +530,16 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
{
transport_len = spprintf(&transport, 0, "tcp://%s:%d", host, port);
}
+ DBG_INF_FMT("transport=%p", transport);
if (conn->persistent) {
struct timeval tv;
gettimeofday(&tv, NULL);
/* We should generate something unique */
- spprintf(&hashed_details, 0, "%s@%s@%s@%ld@%ld@%0.8F",
- transport, user, db, tv.tv_sec, (long int)tv.tv_usec,
- php_combined_lcg(TSRMLS_C) * 10);
+ hashed_details_len = spprintf(&hashed_details, 0, "%s@%s@%s@%ld@%ld@%0.8F",
+ transport, user, db, tv.tv_sec, (long int)tv.tv_usec,
+ php_combined_lcg(TSRMLS_C) * 10);
+ DBG_INF_FMT("hashed_details=%s", hashed_details);
}
PACKET_INIT_ALLOCA(greet_packet, PROT_GREET_PACKET);
@@ -496,17 +560,43 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
}
if (conn->persistent) {
conn->scheme = pestrndup(transport, transport_len, 1);
- efree(transport);
+ mnd_efree(transport);
} else {
conn->scheme = transport;
}
+ DBG_INF(conn->scheme);
conn->net.stream = php_stream_xport_create(conn->scheme, transport_len, streams_options, streams_flags,
hashed_details,
(conn->options.timeout_connect) ? &tv : NULL,
NULL /*ctx*/, &errstr, &errcode);
+ DBG_INF_FMT("stream=%p", conn->net.stream);
+
if (hashed_details) {
- efree(hashed_details);
+ /*
+ If persistent, the streams register it in EG(persistent_list).
+ This is unwanted. ext/mysql or ext/mysqli are responsible to clean,
+ whatever they have to.
+ */
+ zend_rsrc_list_entry *le;
+
+ if (zend_hash_find(&EG(persistent_list), hashed_details, hashed_details_len + 1,
+ (void*) &le) == SUCCESS) {
+ /*
+ in_free will let streams code skip destructing - big HACK,
+ but STREAMS suck big time regarding persistent streams.
+ Just not compatible for extensions that need persistency.
+ */
+ conn->net.stream->in_free = 1;
+ zend_hash_del(&EG(persistent_list), hashed_details, hashed_details_len + 1);
+ conn->net.stream->in_free = 0;
+ }
+#if ZEND_DEBUG
+ /* Shut-up the streams, they don't know what they are doing */
+ conn->net.stream->__exposed = 1;
+#endif
+ mnd_efree(hashed_details);
}
+
if (errstr || !conn->net.stream) {
goto err;
}
@@ -524,15 +614,17 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
}
if (FAIL == PACKET_READ_ALLOCA(greet_packet, conn)) {
-#ifndef MYSQLND_SILENT
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading greeting packet");
-#endif
+ DBG_ERR("Error while reading greeting packet");
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading greeting packet. PID=%d", getpid());
goto err;
} else if (greet_packet.error_no) {
+ DBG_ERR_FMT("errorno=%d error=%s", greet_packet.error_no, greet_packet.error);
SET_CLIENT_ERROR(conn->error_info, greet_packet.error_no,
greet_packet.sqlstate, greet_packet.error);
goto err;
} else if (greet_packet.pre41) {
+ DBG_ERR_FMT("Connecting to 3.22, 3.23 & 4.0 is not supported. Server is %-.32s",
+ greet_packet.server_version);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connecting to 3.22, 3.23 & 4.0 "
" is not supported. Server is %-.32s", greet_packet.server_version);
SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE,
@@ -545,6 +637,7 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
conn->server_version = greet_packet.server_version;
greet_packet.server_version = NULL; /* The string will be freed otherwise */
+ conn->greet_charset = mysqlnd_find_charset_nr(greet_packet.charset_no);
/* we allow load data local infile by default */
mysql_flags |= CLIENT_LOCAL_FILES;
@@ -567,23 +660,26 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
auth_packet->max_packet_size= 3UL*1024UL*1024UL*1024UL;
auth_packet->client_flags= mysql_flags;
- conn->scramble = auth_packet->server_scramble_buf = pemalloc(SCRAMBLE_LENGTH, conn->persistent);
+ conn->scramble = auth_packet->server_scramble_buf = mnd_pemalloc(SCRAMBLE_LENGTH, conn->persistent);
memcpy(auth_packet->server_scramble_buf, greet_packet.scramble_buf, SCRAMBLE_LENGTH);
- PACKET_WRITE(auth_packet, conn);
+ if (!PACKET_WRITE(auth_packet, conn)) {
+ conn->state = CONN_QUIT_SENT;
+ SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
+ goto err;
+ }
if (FAIL == PACKET_READ_ALLOCA(ok_packet, conn) || ok_packet.field_count >= 0xFE) {
if (ok_packet.field_count == 0xFE) {
/* old authentication with new server !*/
+ DBG_ERR("mysqlnd cannot connect to MySQL 4.1+ using old authentication");
php_error_docref(NULL TSRMLS_CC, E_WARNING, "mysqlnd cannot connect to MySQL 4.1+ using old authentication");
} else if (ok_packet.field_count == 0xFF) {
if (ok_packet.sqlstate[0]) {
if (!self_alloced) {
strncpy(conn->error_info.sqlstate, ok_packet.sqlstate, sizeof(conn->error_info.sqlstate));
}
-#ifndef MYSQLND_SILENT
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "ERROR:%d [SQLSTATE:%s] %s",
- ok_packet.error_no, ok_packet.sqlstate, ok_packet.error);
-#endif
+ DBG_ERR_FMT("ERROR:%d [SQLSTATE:%s] %s",
+ ok_packet.error_no, ok_packet.sqlstate, ok_packet.error);
}
if (!self_alloced) {
conn->error_info.error_no = ok_packet.error_no;
@@ -603,7 +699,7 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
spprintf(&p, 0, "MySQL host info: %s via TCP/IP", conn->host);
if (conn->persistent) {
conn->host_info = pestrdup(p, 1);
- efree(p);
+ mnd_efree(p);
} else {
conn->host_info = p;
}
@@ -631,17 +727,39 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
conn->zval_cache = mysqlnd_palloc_get_thd_cache_reference(zval_cache);
conn->net.cmd_buffer.length = 128L*1024L;
- conn->net.cmd_buffer.buffer = pemalloc(conn->net.cmd_buffer.length, conn->persistent);
+ conn->net.cmd_buffer.buffer = mnd_pemalloc(conn->net.cmd_buffer.length, conn->persistent);
+
+ mysqlnd_local_infile_default(conn);
+ {
+ uint buf_size;
+ buf_size = MYSQLND_G(net_read_buffer_size); /* this is long, cast to uint*/
+ conn->m->set_client_option(conn, MYSQLND_OPT_NET_READ_BUFFER_SIZE,
+ (char *)&buf_size TSRMLS_CC);
+
+ buf_size = MYSQLND_G(net_cmd_buffer_size); /* this is long, cast to uint*/
+ conn->m->set_client_option(conn, MYSQLND_OPT_NET_CMD_BUFFER_SIZE,
+ (char *)&buf_size TSRMLS_CC);
+ }
MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_CONNECT_SUCCESS);
+ if (reconnect) {
+ MYSQLND_INC_GLOBAL_STATISTIC(STAT_RECONNECT);
+ }
+ MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_OPENED_CONNECTIONS);
+ if (conn->persistent) {
+ MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_OPENED_PERSISTENT_CONNECTIONS);
+ }
+ DBG_INF_FMT("connection_id=%llu", conn->thread_id);
+#if PHP_MAJOR_VERSION >= 6
{
uint as_unicode = 1;
conn->m->set_client_option(conn, MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE,
- (char *)&as_unicode);
+ (char *)&as_unicode TSRMLS_CC);
+ DBG_INF("unicode set");
}
-
- return conn;
+#endif
+ DBG_RETURN(conn);
}
err:
PACKET_FREE_ALLOCA(greet_packet);
@@ -649,14 +767,15 @@ err:
PACKET_FREE_ALLOCA(ok_packet);
if (errstr) {
+ DBG_ERR_FMT("[%d] %.64s (trying to connect via %s)", errcode, errstr, conn->scheme);
SET_CLIENT_ERROR(conn->error_info, errcode, UNKNOWN_SQLSTATE, errstr);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "[%d] %.64s (trying to connect via %s)", errcode, errstr, conn->scheme);
- efree(errstr);
+ mnd_efree(errstr);
}
if (conn->scheme) {
- pefree(conn->scheme, conn->persistent);
+ mnd_pefree(conn->scheme, conn->persistent);
conn->scheme = NULL;
}
@@ -673,7 +792,7 @@ err:
} else {
MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_CONNECT_FAILURE);
}
- return NULL;
+ DBG_RETURN(NULL);
}
/* }}} */
@@ -687,11 +806,13 @@ static enum_func_status
MYSQLND_METHOD(mysqlnd_conn, query)(MYSQLND *conn, const char *query, unsigned int query_len TSRMLS_DC)
{
enum_func_status ret;
+ DBG_ENTER("mysqlnd_conn::query");
+ DBG_INF_FMT("conn=%llu query=%s", conn->thread_id, query);
if (PASS != mysqlnd_simple_command(conn, COM_QUERY, query, query_len,
PROT_LAST /* we will handle the OK packet*/,
FALSE TSRMLS_CC)) {
- return FAIL;
+ DBG_RETURN(FAIL);
}
/*
@@ -699,21 +820,82 @@ MYSQLND_METHOD(mysqlnd_conn, query)(MYSQLND *conn, const char *query, unsigned i
information from the ok packet. We will fetch it ourselves.
*/
ret = mysqlnd_query_read_result_set_header(conn, NULL TSRMLS_CC);
-
- return ret;
+ DBG_RETURN(ret);
}
/* }}} */
+/*
+ COM_FIELD_LIST is special, different from a SHOW FIELDS FROM :
+ - There is no result set header - status from the command, which
+ impacts us to allocate big chunk of memory for reading the metadata.
+ - The EOF packet is consumed by the metadata packet reader.
+*/
+
+/* {{{ mysqlnd_conn::list_fields */
+MYSQLND_RES *
+MYSQLND_METHOD(mysqlnd_conn, list_fields)(MYSQLND *conn, const char *table, const char *achtung_wild TSRMLS_DC)
+{
+ /* db + \0 + wild + \0 (for wild) */
+ char buff[MYSQLND_MAX_ALLOWED_DB_LEN * 4 * 2 + 1 + 1], *p;
+ size_t table_len, wild_len;
+ MYSQLND_RES *result = NULL;
+ DBG_ENTER("mysqlnd_conn::list_fields");
+ DBG_INF_FMT("conn=%llu table=%s wild=%s", conn->thread_id, table? table:"",achtung_wild? achtung_wild:"");
+
+ p = buff;
+ if (table && (table_len = strlen(table))) {
+ memcpy(p, table, MIN(table_len, MYSQLND_MAX_ALLOWED_DB_LEN * 4));
+ p += table_len;
+ *p++ = '\0';
+ }
+
+ if (achtung_wild && (wild_len = strlen(achtung_wild))) {
+ memcpy(p, achtung_wild, MIN(wild_len, MYSQLND_MAX_ALLOWED_DB_LEN * 4));
+ p += wild_len;
+ *p++ = '\0';
+ }
+
+ if (PASS != mysqlnd_simple_command(conn, COM_FIELD_LIST, buff, p - buff,
+ PROT_LAST /* we will handle the OK packet*/,
+ FALSE TSRMLS_CC)) {
+ DBG_RETURN(NULL);
+ }
+ /*
+ Prepare for the worst case.
+ MyISAM goes to 2500 BIT columns, double it for safety.
+ */
+ result = mysqlnd_result_init(5000, mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache) TSRMLS_CC);
+
+
+ if (FAIL == result->m.read_result_metadata(result, conn TSRMLS_CC)) {
+ DBG_ERR("Error ocurred while reading metadata");
+ result->m.free_result(result, TRUE TSRMLS_CC);
+ DBG_RETURN(NULL);
+ }
+
+ result->type = MYSQLND_RES_NORMAL;
+ result->m.fetch_row = result->m.fetch_row_normal_unbuffered;
+ result->unbuf = mnd_ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
+ result->unbuf->eof_reached = TRUE;
+
+ DBG_RETURN(result);
+}
+/* }}} */
+
/* {{{ mysqlnd_conn::list_method */
MYSQLND_RES *
-MYSQLND_METHOD(mysqlnd_conn, list_method)(MYSQLND *conn, const char *query, char *achtung_wild, char *par1 TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_conn, list_method)(MYSQLND *conn, const char *query,
+ const char *achtung_wild, char *par1 TSRMLS_DC)
{
char *show_query = NULL;
size_t show_query_len;
MYSQLND_RES *result = NULL;
+ DBG_ENTER("mysqlnd_conn::list_method");
+ DBG_INF_FMT("conn=%llu query=%s wild=%d", conn->thread_id, query, achtung_wild);
+
if (par1) {
if (achtung_wild) {
show_query_len = spprintf(&show_query, 0, query, par1, achtung_wild);
@@ -732,12 +914,13 @@ MYSQLND_METHOD(mysqlnd_conn, list_method)(MYSQLND *conn, const char *query, char
result = conn->m->store_result(conn TSRMLS_CC);
}
if (show_query != query) {
- efree(show_query);
+ mnd_efree(show_query);
}
- return result;
+ DBG_RETURN(result);
}
/* }}} */
+
/* {{{ mysqlnd_conn::errno */
static unsigned int
MYSQLND_METHOD(mysqlnd_conn, errno)(const MYSQLND * const conn)
@@ -766,22 +949,26 @@ MYSQLND_METHOD(mysqlnd_conn, sqlstate)(const MYSQLND * const conn)
/* {{{ mysqlnd_old_escape_string */
-PHPAPI ulong mysqlnd_old_escape_string(char *newstr, const char *escapestr, int escapestr_len)
+PHPAPI ulong mysqlnd_old_escape_string(char *newstr, const char *escapestr, int escapestr_len TSRMLS_DC)
{
- return mysqlnd_cset_escape_slashes(mysqlnd_find_charset_name("latin1"),
- newstr, escapestr, escapestr_len);
+ DBG_ENTER("mysqlnd_old_escape_string");
+ DBG_RETURN(mysqlnd_cset_escape_slashes(mysqlnd_find_charset_name("latin1"),
+ newstr, escapestr, escapestr_len TSRMLS_CC));
}
/* }}} */
/* {{{ mysqlnd_conn::escape_string */
static ulong
-MYSQLND_METHOD(mysqlnd_conn, escape_string)(const MYSQLND * const conn, char *newstr, const char *escapestr, int escapestr_len)
+MYSQLND_METHOD(mysqlnd_conn, escape_string)(const MYSQLND * const conn, char *newstr,
+ const char *escapestr, int escapestr_len TSRMLS_DC)
{
+ DBG_ENTER("mysqlnd_conn::escape_string");
+ DBG_INF_FMT("conn=%llu", conn->thread_id);
if (conn->upsert_status.server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES) {
- return mysqlnd_cset_escape_quotes(conn->charset, newstr, escapestr, escapestr_len);
+ DBG_RETURN(mysqlnd_cset_escape_quotes(conn->charset, newstr, escapestr, escapestr_len TSRMLS_CC));
}
- return mysqlnd_cset_escape_slashes(conn->charset, newstr, escapestr, escapestr_len);
+ DBG_RETURN(mysqlnd_cset_escape_slashes(conn->charset, newstr, escapestr, escapestr_len TSRMLS_CC));
}
/* }}} */
@@ -790,7 +977,9 @@ MYSQLND_METHOD(mysqlnd_conn, escape_string)(const MYSQLND * const conn, char *ne
static enum_func_status
MYSQLND_METHOD(mysqlnd_conn, dump_debug_info)(MYSQLND * const conn TSRMLS_DC)
{
- return mysqlnd_simple_command(conn, COM_DEBUG, NULL, 0, PROT_EOF_PACKET, FALSE TSRMLS_CC);
+ DBG_ENTER("mysqlnd_conn::dump_debug_info");
+ DBG_INF_FMT("conn=%llu", conn->thread_id);
+ DBG_RETURN(mysqlnd_simple_command(conn, COM_DEBUG, NULL, 0, PROT_EOF_PACKET, FALSE TSRMLS_CC));
}
/* }}} */
@@ -802,6 +991,10 @@ MYSQLND_METHOD(mysqlnd_conn, select_db)(MYSQLND * const conn,
unsigned int db_len TSRMLS_DC)
{
enum_func_status ret;
+
+ DBG_ENTER("mysqlnd_conn::select_db");
+ DBG_INF_FMT("conn=%llu db=%s", conn->thread_id, db);
+
ret = mysqlnd_simple_command(conn, COM_INIT_DB, db, db_len, PROT_OK_PACKET, FALSE TSRMLS_CC);
/*
The server sends 0 but libmysql doesn't read it and has established
@@ -809,7 +1002,7 @@ MYSQLND_METHOD(mysqlnd_conn, select_db)(MYSQLND * const conn,
*/
SET_ERROR_AFF_ROWS(conn);
- return ret;
+ DBG_RETURN(ret);
}
/* }}} */
@@ -819,14 +1012,19 @@ static enum_func_status
MYSQLND_METHOD(mysqlnd_conn, ping)(MYSQLND * const conn TSRMLS_DC)
{
enum_func_status ret;
- ret = mysqlnd_simple_command(conn, COM_PING, NULL, 0, PROT_OK_PACKET, FALSE TSRMLS_CC);
+
+ DBG_ENTER("mysqlnd_conn::ping");
+ DBG_INF_FMT("conn=%llu", conn->thread_id);
+
+ ret = mysqlnd_simple_command(conn, COM_PING, NULL, 0, PROT_OK_PACKET, TRUE TSRMLS_CC);
/*
The server sends 0 but libmysql doesn't read it and has established
a protocol of giving back -1. Thus we have to follow it :(
*/
SET_ERROR_AFF_ROWS(conn);
- return ret;
+ DBG_INF_FMT("ret=%d", ret);
+ DBG_RETURN(ret);
}
/* }}} */
@@ -838,13 +1036,16 @@ MYSQLND_METHOD(mysqlnd_conn, stat)(MYSQLND *conn, char **message, unsigned int *
enum_func_status ret;
php_mysql_packet_stats stats_header;
+ DBG_ENTER("mysqlnd_conn::stat");
+ DBG_INF_FMT("conn=%llu", conn->thread_id);
+
ret = mysqlnd_simple_command(conn, COM_STATISTICS, NULL, 0, PROT_LAST, FALSE TSRMLS_CC);
if (FAIL == ret) {
- return FAIL;
+ DBG_RETURN(FAIL);
}
PACKET_INIT_ALLOCA(stats_header, PROT_STATS_PACKET);
if (FAIL == (ret = PACKET_READ_ALLOCA(stats_header, conn))) {
- return FAIL;
+ DBG_RETURN(FAIL);
}
*message = stats_header.message;
*message_len = stats_header.message_len;
@@ -852,18 +1053,22 @@ MYSQLND_METHOD(mysqlnd_conn, stat)(MYSQLND *conn, char **message, unsigned int *
stats_header.message = NULL;
PACKET_FREE_ALLOCA(stats_header);
- return PASS;
+ DBG_INF(*message);
+ DBG_RETURN(PASS);
}
/* }}} */
/* {{{ mysqlnd_conn::kill */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_conn, kill)(MYSQLND *conn, unsigned long pid TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_conn, kill)(MYSQLND *conn, unsigned int pid TSRMLS_DC)
{
enum_func_status ret;
char buff[4];
+ DBG_ENTER("mysqlnd_conn::kill");
+ DBG_INF_FMT("conn=%llu pid=%lu", conn->thread_id, pid);
+
int4store(buff, pid);
/* If we kill ourselves don't expect OK packet, PROT_LAST will skip it */
@@ -878,7 +1083,7 @@ MYSQLND_METHOD(mysqlnd_conn, kill)(MYSQLND *conn, unsigned long pid TSRMLS_DC)
4, PROT_LAST, FALSE TSRMLS_CC))) {
conn->state = CONN_QUIT_SENT;
}
- return ret;
+ DBG_RETURN(ret);
}
/* }}} */
@@ -892,10 +1097,13 @@ MYSQLND_METHOD(mysqlnd_conn, set_charset)(MYSQLND * const conn, const char * con
size_t query_len;
const MYSQLND_CHARSET * const charset = mysqlnd_find_charset_name(csname);
+ DBG_ENTER("mysqlnd_conn::set_charset");
+ DBG_INF_FMT("conn=%llu cs=%s", conn->thread_id, csname);
+
if (!charset) {
SET_CLIENT_ERROR(conn->error_info, CR_CANT_FIND_CHARSET, UNKNOWN_SQLSTATE,
"Invalid characterset or character set not supported");
- return FAIL;
+ DBG_RETURN(FAIL);
}
query_len = spprintf(&query, 0, "SET NAMES %s", csname);
@@ -907,8 +1115,10 @@ MYSQLND_METHOD(mysqlnd_conn, set_charset)(MYSQLND * const conn, const char * con
} else {
conn->charset = charset;
}
- efree(query);
- return ret;
+ mnd_efree(query);
+
+ DBG_INF(ret == PASS? "PASS":"FAIL");
+ DBG_RETURN(ret);
}
/* }}} */
@@ -918,9 +1128,12 @@ static enum_func_status
MYSQLND_METHOD(mysqlnd_conn, refresh)(MYSQLND * const conn, unsigned long options TSRMLS_DC)
{
zend_uchar bits[1];
+ DBG_ENTER("mysqlnd_conn::refresh");
+ DBG_INF_FMT("conn=%llu options=%lu", conn->thread_id, options);
+
int1store(bits, options);
- return mysqlnd_simple_command(conn, COM_REFRESH, (char *)bits, 1, PROT_OK_PACKET, FALSE TSRMLS_CC);
+ DBG_RETURN(mysqlnd_simple_command(conn, COM_REFRESH, (char *)bits, 1, PROT_OK_PACKET, FALSE TSRMLS_CC));
}
/* }}} */
@@ -930,22 +1143,31 @@ static enum_func_status
MYSQLND_METHOD(mysqlnd_conn, shutdown)(MYSQLND * const conn, unsigned long level TSRMLS_DC)
{
zend_uchar bits[1];
+ DBG_ENTER("mysqlnd_conn::shutdown");
+ DBG_INF_FMT("conn=%llu level=%lu", conn->thread_id, level);
+
int1store(bits, level);
- return mysqlnd_simple_command(conn, COM_SHUTDOWN, (char *)bits, 1, PROT_OK_PACKET, FALSE TSRMLS_CC);
+ DBG_RETURN(mysqlnd_simple_command(conn, COM_SHUTDOWN, (char *)bits, 1, PROT_OK_PACKET, FALSE TSRMLS_CC));
}
/* }}} */
/* {{{ mysqlnd_send_close */
-static enum_func_status
+enum_func_status
mysqlnd_send_close(MYSQLND * conn TSRMLS_DC)
{
enum_func_status ret = PASS;
+
+ DBG_ENTER("mysqlnd_send_close");
+ DBG_INF_FMT("conn=%llu conn->net.stream->abstract=%p",
+ conn->thread_id, conn->net.stream? conn->net.stream->abstract:NULL);
+
switch (conn->state) {
case CONN_READY:
+ DBG_INF("Connection clean, sending COM_QUIT");
ret = mysqlnd_simple_command(conn, COM_QUIT, NULL, 0, PROT_LAST,
- conn->tmp_int? TRUE : FALSE TSRMLS_CC);
+ TRUE TSRMLS_CC);
/* Do nothing */
break;
case CONN_SENDING_LOAD_DATA:
@@ -956,10 +1178,8 @@ mysqlnd_send_close(MYSQLND * conn TSRMLS_DC)
case CONN_NEXT_RESULT_PENDING:
case CONN_QUERY_SENT:
case CONN_FETCHING_DATA:
- MYSQLND_INC_CONN_STATISTIC(NULL, STAT_CLOSE_IN_MIDDLE);
-#ifndef MYSQLND_SILENT
- php_printf("Brutally closing connection [%p][%s]\n", conn, conn->scheme);
-#endif
+ MYSQLND_INC_GLOBAL_STATISTIC(STAT_CLOSE_IN_MIDDLE);
+ DBG_ERR_FMT("Brutally closing connection [%p][%s]", conn, conn->scheme);
/*
Do nothing, the connection will be brutally closed
and the server will catch it and free close from its side.
@@ -981,7 +1201,7 @@ mysqlnd_send_close(MYSQLND * conn TSRMLS_DC)
*/
conn->state = CONN_QUIT_SENT;
- return ret;
+ DBG_RETURN(ret);
}
/* }}} */
@@ -999,13 +1219,25 @@ MYSQLND_METHOD(mysqlnd_conn, close)(MYSQLND * conn, enum_connection_close_type c
};
enum_mysqlnd_collected_stats stat = close_type_to_stat_map[close_type];
- MYSQLND_INC_CONN_STATISTIC(NULL, stat);
+ DBG_ENTER("mysqlnd_conn::close");
+ DBG_INF_FMT("conn=%llu", conn->thread_id);
- mysqlnd_send_close(conn TSRMLS_CC);
+ MYSQLND_INC_CONN_STATISTIC(&conn->stats, stat);
+ MYSQLND_DEC_CONN_STATISTIC(&conn->stats, STAT_OPENED_CONNECTIONS);
+ if (conn->persistent) {
+ MYSQLND_DEC_CONN_STATISTIC(&conn->stats, STAT_OPENED_PERSISTENT_CONNECTIONS);
+ }
- conn->m->free_reference(conn TSRMLS_CC);
+ /*
+ Close now, free_reference will try,
+ if we are last, but that's not a problem.
+ */
+ ret = mysqlnd_send_close(conn TSRMLS_CC);
+
+ ret = conn->m->free_reference(conn TSRMLS_CC);
- return ret;
+
+ DBG_RETURN(ret);
}
/* }}} */
@@ -1021,18 +1253,22 @@ MYSQLND_METHOD_PRIVATE(mysqlnd_conn, get_reference)(MYSQLND * const conn)
/* {{{ mysqlnd_conn::free_reference */
-static void
+static enum_func_status
MYSQLND_METHOD_PRIVATE(mysqlnd_conn, free_reference)(MYSQLND * const conn TSRMLS_DC)
{
+ enum_func_status ret = PASS;
+ DBG_ENTER("mysqlnd_conn::free_reference");
+ DBG_INF_FMT("conn=%llu conn->refcount=%u", conn->thread_id, conn->refcount);
if (!(--conn->refcount)) {
/*
No multithreading issues as we don't share the connection :)
This will free the object too, of course because references has
reached zero.
*/
- mysqlnd_send_close(conn TSRMLS_CC);
+ ret = mysqlnd_send_close(conn TSRMLS_CC);
conn->m->dtor(conn TSRMLS_CC);
}
+ DBG_RETURN(ret);
}
/* }}} */
@@ -1181,8 +1417,11 @@ MYSQLND_METHOD(mysqlnd_conn, next_result)(MYSQLND * const conn TSRMLS_DC)
{
enum_func_status ret;
+ DBG_ENTER("mysqlnd_conn::next_result");
+ DBG_INF_FMT("conn=%llu", conn->thread_id);
+
if (conn->state != CONN_NEXT_RESULT_PENDING) {
- return FAIL;
+ DBG_RETURN(FAIL);
}
SET_EMPTY_ERROR(conn->error_info);
@@ -1192,13 +1431,12 @@ MYSQLND_METHOD(mysqlnd_conn, next_result)(MYSQLND * const conn TSRMLS_DC)
in mysqlnd_store_result() or mysqlnd_fetch_row_unbuffered()
*/
if (FAIL == (ret = mysqlnd_query_read_result_set_header(conn, NULL TSRMLS_CC))) {
-#ifndef MYSQLND_SILENT
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Serious error");
-#endif
+ DBG_ERR_FMT("Serious error. %s::%d", __FILE__, __LINE__);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Serious error. PID=%d", getpid());
conn->state = CONN_QUIT_SENT;
}
- return ret;
+ DBG_RETURN(ret);
}
/* }}} */
@@ -1272,6 +1510,10 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn,
char buffer[MYSQLND_MAX_ALLOWED_USER_LEN + 1 + SCRAMBLE_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1];
char *p = buffer;
+ DBG_ENTER("mysqlnd_conn::change_user");
+ DBG_INF_FMT("conn=%llu user=%s passwd=%s db=%s",
+ conn->thread_id, user?user:"", passwd?"***":"null", db?db:"");
+
if (!user) {
user = "";
}
@@ -1283,8 +1525,8 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn,
}
/* 1. user ASCIIZ */
- user_len = strlen(user);
- memcpy(p, user, MIN(user_len, MYSQLND_MAX_ALLOWED_DB_LEN));
+ user_len = MIN(strlen(user), MYSQLND_MAX_ALLOWED_DB_LEN);
+ memcpy(p, user, user_len);
p += user_len;
*p++ = '\0';
@@ -1308,7 +1550,7 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn,
if (PASS != mysqlnd_simple_command(conn, COM_CHANGE_USER, buffer, p - buffer,
PROT_LAST /* we will handle the OK packet*/,
FALSE TSRMLS_CC)) {
- return FAIL;
+ DBG_RETURN(FAIL);
}
PACKET_INIT_ALLOCA(chg_user_resp, PROT_CHG_USER_PACKET);
@@ -1330,15 +1572,30 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn,
PACKET_INIT_ALLOCA(redundant_error_packet, PROT_OK_PACKET);
PACKET_READ_ALLOCA(redundant_error_packet, conn);
PACKET_FREE_ALLOCA(redundant_error_packet);
+ DBG_INF_FMT("Server is %d, buggy, sends two ERR messages", mysqlnd_get_server_version(conn));
}
}
+ if (ret == PASS) {
+ mnd_pefree(conn->user, conn->persistent);
+ conn->user = pestrndup(user, user_len, conn->persistent);
+ mnd_pefree(conn->passwd, conn->persistent);
+ conn->passwd = pestrdup(passwd, conn->persistent);
+ if (conn->last_message) {
+ mnd_pefree(conn->last_message, conn->persistent);
+ conn->last_message = NULL;
+ }
+ conn->charset = conn->greet_charset;
+ memset(&conn->upsert_status, 0, sizeof(conn->upsert_status));
+ }
+
+ SET_ERROR_AFF_ROWS(conn);
/*
Here we should close all statements. Unbuffered queries should not be a
problem as we won't allow sending COM_CHANGE_USER.
*/
-
- return ret;
+ DBG_INF(ret == PASS? "PASS":"FAIL");
+ DBG_RETURN(ret);
}
/* }}} */
@@ -1347,12 +1604,30 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn,
static enum_func_status
MYSQLND_METHOD(mysqlnd_conn, set_client_option)(MYSQLND * const conn,
enum mysqlnd_option option,
- const char * const value)
+ const char * const value
+ TSRMLS_DC)
{
+ DBG_ENTER("mysqlnd_conn::set_client_option");
+ DBG_INF_FMT("conn=%llu option=%d", conn->thread_id, option);
switch (option) {
+#if PHP_MAJOR_VERSION >= 6
case MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE:
conn->options.numeric_and_datetime_as_unicode = *(uint*) value;
break;
+#endif
+ case MYSQLND_OPT_NET_CMD_BUFFER_SIZE:
+ conn->net.cmd_buffer.length = *(uint*) value;
+ if (!conn->net.cmd_buffer.buffer) {
+ conn->net.cmd_buffer.buffer = mnd_pemalloc(conn->net.cmd_buffer.length, conn->persistent);
+ } else {
+ conn->net.cmd_buffer.buffer = mnd_perealloc(conn->net.cmd_buffer.buffer,
+ conn->net.cmd_buffer.length,
+ conn->persistent);
+ }
+ break;
+ case MYSQLND_OPT_NET_READ_BUFFER_SIZE:
+ conn->options.net_read_buffer_size = *(uint*) value;
+ break;
#ifdef MYSQLND_STRING_TO_INT_CONVERSION
case MYSQLND_OPT_INT_AND_YEAR_AS_INT:
conn->options.int_and_year_as_int = *(uint*) value;
@@ -1414,9 +1689,9 @@ MYSQLND_METHOD(mysqlnd_conn, set_client_option)(MYSQLND * const conn,
/* not sure, todo ? */
#endif
default:
- return FAIL;
+ DBG_RETURN(FAIL);
}
- return PASS;
+ DBG_RETURN(PASS);
}
/* }}} */
@@ -1427,15 +1702,19 @@ MYSQLND_METHOD(mysqlnd_conn, use_result)(MYSQLND * const conn TSRMLS_DC)
{
MYSQLND_RES *result;
+ DBG_ENTER("mysqlnd_conn::use_result");
+ DBG_INF_FMT("conn=%llu", conn->thread_id);
+
if (!conn->current_result) {
- return NULL;
+ DBG_RETURN(NULL);
}
/* Nothing to store for UPSERT/LOAD DATA */
if (conn->last_query_type != QUERY_SELECT || conn->state != CONN_FETCHING_DATA) {
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
- mysqlnd_out_of_sync);
- return NULL;
+ mysqlnd_out_of_sync);
+ DBG_ERR("Command out of sync");
+ DBG_RETURN(NULL);
}
MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_UNBUFFERED_SETS);
@@ -1444,7 +1723,8 @@ MYSQLND_METHOD(mysqlnd_conn, use_result)(MYSQLND * const conn TSRMLS_DC)
conn->current_result = NULL;
result->conn = conn->m->get_reference(conn);
- return result->m.use_result(result, FALSE TSRMLS_CC);
+ result = result->m.use_result(result, FALSE TSRMLS_CC);
+ DBG_RETURN(result);
}
/* }}} */
@@ -1455,15 +1735,19 @@ MYSQLND_METHOD(mysqlnd_conn, store_result)(MYSQLND * const conn TSRMLS_DC)
{
MYSQLND_RES *result;
+ DBG_ENTER("mysqlnd_conn::store_result");
+ DBG_INF_FMT("conn=%llu", conn->thread_id);
+
if (!conn->current_result) {
- return NULL;
+ DBG_RETURN(NULL);
}
/* Nothing to store for UPSERT/LOAD DATA*/
if (conn->last_query_type != QUERY_SELECT || conn->state != CONN_FETCHING_DATA) {
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
mysqlnd_out_of_sync);
- return NULL;
+ DBG_ERR("Command out of sync");
+ DBG_RETURN(NULL);
}
MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_BUFFERED_SETS);
@@ -1471,7 +1755,8 @@ MYSQLND_METHOD(mysqlnd_conn, store_result)(MYSQLND * const conn TSRMLS_DC)
result = conn->current_result;
conn->current_result = NULL;
- return result->m.store_result(result, conn, FALSE TSRMLS_CC);
+ result = result->m.store_result(result, conn, FALSE TSRMLS_CC);
+ DBG_RETURN(result);
}
/* }}} */
@@ -1482,12 +1767,15 @@ MYSQLND_METHOD(mysqlnd_conn, get_connection_stats)(const MYSQLND * const conn,
zval *return_value
TSRMLS_DC ZEND_FILE_LINE_DC)
{
+ DBG_ENTER("mysqlnd_conn::get_connection_stats");
+ DBG_INF_FMT("conn=%llu", conn->thread_id);
mysqlnd_fill_stats_hash(&(conn->stats), return_value TSRMLS_CC ZEND_FILE_LINE_CC);
+ DBG_VOID_RETURN;
}
/* }}} */
-MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND * const conn);
+MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND * const conn TSRMLS_DC);
MYSQLND_CLASS_METHODS_START(mysqlnd_conn)
@@ -1524,6 +1812,7 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_conn)
MYSQLND_METHOD(mysqlnd_conn, get_proto_info),
MYSQLND_METHOD(mysqlnd_conn, info),
MYSQLND_METHOD(mysqlnd_conn, charset_name),
+ MYSQLND_METHOD(mysqlnd_conn, list_fields),
MYSQLND_METHOD(mysqlnd_conn, list_method),
MYSQLND_METHOD(mysqlnd_conn, insert_id),
@@ -1544,16 +1833,20 @@ MYSQLND_CLASS_METHODS_END;
/* {{{ mysqlnd_init */
-PHPAPI MYSQLND *mysqlnd_init(zend_bool persistent)
+PHPAPI MYSQLND *_mysqlnd_init(zend_bool persistent TSRMLS_DC)
{
- MYSQLND *ret = pecalloc(1, sizeof(MYSQLND), persistent);
+ MYSQLND *ret = mnd_pecalloc(1, sizeof(MYSQLND), persistent);
+
+ DBG_ENTER("mysqlnd_init");
+ DBG_INF_FMT("persistent=%d", persistent);
+
SET_ERROR_AFF_ROWS(ret);
ret->persistent = persistent;
ret->m = & mysqlnd_mysqlnd_conn_methods;
ret->m->get_reference(ret);
- return ret;
+ DBG_RETURN(ret);
}
/* }}} */
@@ -1562,7 +1855,7 @@ PHPAPI MYSQLND *mysqlnd_init(zend_bool persistent)
*
* Every user visible function must have an entry in mysqlnd_functions[].
*/
-static const zend_function_entry mysqlnd_functions[] = {
+static zend_function_entry mysqlnd_functions[] = {
{NULL, NULL, NULL} /* Must be the last line in mysqlnd_functions[] */
};
/* }}} */
@@ -1595,7 +1888,7 @@ PHPAPI void mysqlnd_minfo_print_hash(zval *values)
php_info_print_table_row(2, s, Z_STRVAL_PP(values_entry));
}
if (s) {
- efree(s);
+ mnd_efree(s);
}
} else {
php_info_print_table_row(2, string_key.s, Z_STRVAL_PP(values_entry));
@@ -1632,6 +1925,7 @@ void mysqlnd_minfo_print_hash(zval *values)
*/
PHP_MINFO_FUNCTION(mysqlnd)
{
+ char buf[32];
zval values;
php_info_print_table_start();
@@ -1642,19 +1936,33 @@ PHP_MINFO_FUNCTION(mysqlnd)
php_info_print_table_header(2, "Client statistics", "");
mysqlnd_get_client_stats(&values);
mysqlnd_minfo_print_hash(&values);
+ php_info_print_table_row(2, "Collecting statistics", MYSQLND_G(collect_statistics)? "Yes":"No");
+ php_info_print_table_row(2, "Collecting memory statistics", MYSQLND_G(collect_memory_statistics)? "Yes":"No");
+
+ snprintf(buf, sizeof(buf), "%ld", MYSQLND_G(net_cmd_buffer_size));
+ php_info_print_table_row(2, "Command buffer size", buf);
+ snprintf(buf, sizeof(buf), "%ld", MYSQLND_G(net_read_buffer_size));
+ php_info_print_table_row(2, "Read buffer size", buf);
+
zval_dtor(&values);
php_info_print_table_end();
}
/* }}} */
-ZEND_DECLARE_MODULE_GLOBALS(mysqlnd)
+ZEND_DECLARE_MODULE_GLOBALS(mysqlnd);
+
/* {{{ PHP_GINIT_FUNCTION
*/
static PHP_GINIT_FUNCTION(mysqlnd)
{
- mysqlnd_globals->collect_statistics = FALSE;
+ mysqlnd_globals->collect_statistics = TRUE;
+ mysqlnd_globals->collect_memory_statistics = FALSE;
+ mysqlnd_globals->debug = NULL; /* The actual string */
+ mysqlnd_globals->dbg = NULL; /* The DBG object*/
+ mysqlnd_globals->net_cmd_buffer_size = 2048;
+ mysqlnd_globals->net_read_buffer_size = 32768;
}
/* }}} */
@@ -1662,7 +1970,11 @@ static PHP_GINIT_FUNCTION(mysqlnd)
/* {{{ PHP_INI_BEGIN
*/
PHP_INI_BEGIN()
- STD_PHP_INI_BOOLEAN("mysqlnd.collect_statistics", "1", PHP_INI_SYSTEM, OnUpdateBool, collect_statistics, zend_mysqlnd_globals, mysqlnd_globals)
+ STD_PHP_INI_BOOLEAN("mysqlnd.collect_statistics", "1", PHP_INI_ALL, OnUpdateBool, collect_statistics, zend_mysqlnd_globals, mysqlnd_globals)
+ STD_PHP_INI_BOOLEAN("mysqlnd.collect_memory_statistics", "0", PHP_INI_SYSTEM, OnUpdateBool, collect_memory_statistics, zend_mysqlnd_globals, mysqlnd_globals)
+ STD_PHP_INI_ENTRY("mysqlnd.debug", NULL, PHP_INI_SYSTEM, OnUpdateString, debug, zend_mysqlnd_globals, mysqlnd_globals)
+ STD_PHP_INI_ENTRY("mysqlnd.net_cmd_buffer_size", "2048", PHP_INI_ALL, OnUpdateLong, net_cmd_buffer_size, zend_mysqlnd_globals, mysqlnd_globals)
+ STD_PHP_INI_ENTRY("mysqlnd.net_read_buffer_size", "32768",PHP_INI_ALL, OnUpdateLong, net_read_buffer_size, zend_mysqlnd_globals, mysqlnd_globals)
PHP_INI_END()
/* }}} */
@@ -1673,7 +1985,7 @@ static PHP_MINIT_FUNCTION(mysqlnd)
{
REGISTER_INI_ENTRIES();
- mysqlnd_library_init(MYSQLND_G(collect_statistics));
+ mysqlnd_library_init();
return SUCCESS;
}
/* }}} */
@@ -1691,6 +2003,45 @@ static PHP_MSHUTDOWN_FUNCTION(mysqlnd)
/* }}} */
+#if PHP_DEBUG
+/* {{{ PHP_RINIT_FUNCTION
+ */
+static PHP_RINIT_FUNCTION(mysqlnd)
+{
+#ifdef PHP_DEBUG
+ if (MYSQLND_G(debug)) {
+ MYSQLND_DEBUG *dbg = mysqlnd_debug_init(TSRMLS_C);
+ if (!dbg) {
+ return FAILURE;
+ }
+ dbg->m->set_mode(dbg, MYSQLND_G(debug));
+ MYSQLND_G(dbg) = dbg;
+ }
+#endif
+ return SUCCESS;
+}
+/* }}} */
+
+
+/* {{{ PHP_RSHUTDOWN_FUNCTION
+ */
+static PHP_RSHUTDOWN_FUNCTION(mysqlnd)
+{
+#ifdef PHP_DEBUG
+ MYSQLND_DEBUG *dbg = MYSQLND_G(dbg);
+ DBG_ENTER("RSHUTDOWN");
+ if (dbg) {
+ dbg->m->close(dbg);
+ dbg->m->free(dbg);
+ MYSQLND_G(dbg) = NULL;
+ }
+#endif
+ return SUCCESS;
+}
+/* }}} */
+#endif
+
+
/* {{{ mysqlnd_module_entry
*/
zend_module_entry mysqlnd_module_entry = {
@@ -1699,8 +2050,13 @@ zend_module_entry mysqlnd_module_entry = {
mysqlnd_functions,
PHP_MINIT(mysqlnd),
PHP_MSHUTDOWN(mysqlnd),
+#if PHP_DEBUG
+ PHP_RINIT(mysqlnd),
+ PHP_RSHUTDOWN(mysqlnd),
+#else
NULL,
NULL,
+#endif
PHP_MINFO(mysqlnd),
MYSQLND_VERSION,
PHP_MODULE_GLOBALS(mysqlnd),