summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorAndrey Hristov <andrey@php.net>2009-11-20 08:12:14 +0000
committerAndrey Hristov <andrey@php.net>2009-11-20 08:12:14 +0000
commit7674c942c7f0a128b3b8a50e248b0b2fe02e41d8 (patch)
tree6bfec21cda060f431baf43a447dc3f3bb4b3c13f /ext
parent4e958fb22d6c2a5c2ba528967e7f6504de9a6a5d (diff)
downloadphp-git-7674c942c7f0a128b3b8a50e248b0b2fe02e41d8.tar.gz
Compressed protocol support + extensibility for mysqlnd
Diffstat (limited to 'ext')
-rw-r--r--ext/mysqlnd/config.w327
-rw-r--r--ext/mysqlnd/config9.m421
-rw-r--r--ext/mysqlnd/mysqlnd.c206
-rw-r--r--ext/mysqlnd/mysqlnd.h11
-rw-r--r--ext/mysqlnd/mysqlnd_charset.c13
-rw-r--r--ext/mysqlnd/mysqlnd_enum_n_def.h2
-rw-r--r--ext/mysqlnd/mysqlnd_loaddata.c4
-rw-r--r--ext/mysqlnd/mysqlnd_priv.h3
-rw-r--r--ext/mysqlnd/mysqlnd_ps.c42
-rw-r--r--ext/mysqlnd/mysqlnd_result.c132
-rw-r--r--ext/mysqlnd/mysqlnd_result.h11
-rw-r--r--ext/mysqlnd/mysqlnd_structs.h65
-rw-r--r--ext/mysqlnd/mysqlnd_wireprotocol.c638
-rw-r--r--ext/mysqlnd/mysqlnd_wireprotocol.h22
-rw-r--r--ext/mysqlnd/php_mysqlnd.c16
15 files changed, 840 insertions, 353 deletions
diff --git a/ext/mysqlnd/config.w32 b/ext/mysqlnd/config.w32
index d495672cf7..00a3f147c0 100644
--- a/ext/mysqlnd/config.w32
+++ b/ext/mysqlnd/config.w32
@@ -21,5 +21,10 @@ if (PHP_MYSQLND != "no") {
"mysqlnd_wireprotocol.c " +
"php_mysqlnd.c";
EXTENSION("mysqlnd", mysqlnd_source, false);
+ if (((PHP_ZLIB=="no") && (CHECK_LIB("zlib_a.lib;zlib.lib", "mysqlnd", PHP_MYSQLND))) ||
+ (PHP_ZLIB_SHARED && CHECK_LIB("zlib.lib", "mysqlnd", PHP_MYSQLND)) || (PHP_ZLIB == "yes" && (!PHP_ZLIB_SHARED)))
+ {
+ AC_DEFINE("MYSQLND_COMPRESSION_ENABLED", 1, "Compression support");
+ }
}
-} \ No newline at end of file
+}
diff --git a/ext/mysqlnd/config9.m4 b/ext/mysqlnd/config9.m4
index 59fd6c74cc..b3b802cd38 100644
--- a/ext/mysqlnd/config9.m4
+++ b/ext/mysqlnd/config9.m4
@@ -2,11 +2,21 @@ dnl
dnl $Id$
dnl config.m4 for mysqlnd driver
+
PHP_ARG_ENABLE(mysqlnd_threading, whether to enable threaded fetch in mysqlnd,
[ --enable-mysqlnd-threading
EXPERIMENTAL: Enable mysqlnd threaded fetch.
Note: This forces ZTS on!], no, no)
+PHP_ARG_ENABLE(disable_mysqlnd_compression_support, whether to disable compressed protocol support in mysqlnd,
+[ --disable-mysqlnd-compression-support
+ Enable support for the MySQL compressed protocol in mysqlnd], yes)
+
+if test -z "$PHP_ZLIB_DIR"; then
+ PHP_ARG_WITH(zlib-dir, for the location of libz,
+ [ --with-zlib-dir[=DIR] mysqlnd: Set the path to libz install prefix], no, no)
+fi
+
dnl If some extension uses mysqlnd it will get compiled in PHP core
if test "$PHP_MYSQLND_ENABLED" = "yes"; then
mysqlnd_sources="mysqlnd.c mysqlnd_charset.c mysqlnd_wireprotocol.c \
@@ -23,6 +33,17 @@ if test "$PHP_MYSQLND_ENABLED" = "yes"; then
PHP_BUILD_THREAD_SAFE
AC_DEFINE([MYSQLND_THREADED], 1, [Use mysqlnd internal threading])
fi
+
+ if test "$PHP_MYSQLND_COMPRESSION_SUPPORT" != "no"; then
+ AC_DEFINE([MYSQLND_COMPRESSION_ENABLED], 1, [Enable compressed protocol support])
+ if test "$PHP_ZLIB_DIR" != "no"; then
+ PHP_ADD_LIBRARY_WITH_PATH(z, $PHP_ZLIB_DIR, MYSQLND_SHARED_LIBADD)
+ MYSQLND_LIBS="$MYSQLND_LIBS -L$PHP_ZLIB_DIR/$PHP_LIBDIR -lz"
+ else
+ PHP_ADD_LIBRARY(z,, MYSQLND_SHARED_LIBADD)
+ MYSQLND_LIBS="$MYSQLND_LIBS -lz"
+ fi
+ fi
fi
if test "$PHP_MYSQLND_ENABLED" = "yes" || test "$PHP_MYSQLI" != "no"; then
diff --git a/ext/mysqlnd/mysqlnd.c b/ext/mysqlnd/mysqlnd.c
index 3e48550bf8..d0de073837 100644
--- a/ext/mysqlnd/mysqlnd.c
+++ b/ext/mysqlnd/mysqlnd.c
@@ -27,9 +27,8 @@
#include "mysqlnd_statistics.h"
#include "mysqlnd_charset.h"
#include "mysqlnd_debug.h"
-#include "mysqlnd_block_alloc.h"
/* for php_get_current_user() */
-#include "ext/standard/basic_functions.h"
+#include "ext/standard/basic_functions.h"
/* the server doesn't support 4byte utf8, but let's make it forward compatible */
#define MYSQLND_MAX_ALLOWED_USER_LEN 256 /* 64 char * 4byte */
@@ -65,7 +64,6 @@ const char * const mysqlnd_out_of_sync = "Commands out of sync; you can't run th
MYSQLND_STATS *mysqlnd_global_stats = NULL;
static zend_bool mysqlnd_library_initted = FALSE;
-
static enum_func_status mysqlnd_send_close(MYSQLND * conn TSRMLS_DC);
static struct st_mysqlnd_conn_methods *mysqlnd_conn_methods;
@@ -153,10 +151,15 @@ MYSQLND_METHOD(mysqlnd_conn, free_contents)(MYSQLND *conn TSRMLS_DC)
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;
}
+#ifdef MYSQLND_COMPRESSION_ENABLED
+ if (conn->net.uncompressed_data) {
+ conn->net.uncompressed_data->free(&conn->net.uncompressed_data TSRMLS_CC);
+ }
+#endif
DBG_INF("Freeing memory of members");
if (conn->host) {
@@ -213,10 +216,6 @@ MYSQLND_METHOD(mysqlnd_conn, free_contents)(MYSQLND *conn TSRMLS_DC)
mysqlnd_palloc_free_thd_cache_reference(&conn->zval_cache);
conn->zval_cache = NULL;
}
- if (conn->result_set_memory_pool) {
- mysqlnd_mempool_destroy(conn->result_set_memory_pool TSRMLS_CC);
- conn->result_set_memory_pool = NULL;
- }
if (conn->qcache) {
DBG_INF("Freeing qcache reference");
mysqlnd_qcache_free_cache_reference(&conn->qcache);
@@ -296,7 +295,7 @@ mysqlnd_simple_command_handle_response(MYSQLND *conn, enum php_mysql_packet_type
if (0xFF == ok_response.field_count) {
/* The server signalled error. Set the error */
SET_CLIENT_ERROR(conn->error_info, ok_response.error_no,
- ok_response.sqlstate, ok_response.error);
+ ok_response.sqlstate, ok_response.error);
ret = FAIL;
/*
Cover a protocol design error: error packet does not
@@ -374,7 +373,7 @@ mysqlnd_simple_command_handle_response(MYSQLND *conn, enum php_mysql_packet_type
enum_func_status
mysqlnd_simple_command(MYSQLND *conn, enum php_mysqlnd_server_command command,
const char * const arg, size_t arg_len,
- enum php_mysql_packet_type ok_packet, zend_bool silent,
+ enum php_mysql_packet_type ok_packet, zend_bool silent,
zend_bool ignore_upsert_status TSRMLS_DC)
{
enum_func_status ret = PASS;
@@ -454,7 +453,7 @@ MYSQLND_METHOD(mysqlnd_conn, set_server_option)(MYSQLND * const conn,
/* {{{ _mysqlnd_restart_psession */
-PHPAPI void _mysqlnd_restart_psession(MYSQLND *conn, MYSQLND_THD_ZVAL_PCACHE *cache TSRMLS_DC)
+PHPAPI void _mysqlnd_restart_psession(MYSQLND *conn, MYSQLND_THD_ZVAL_PCACHE *cache TSRMLS_DC)
{
DBG_ENTER("_mysqlnd_restart_psession");
MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_CONNECT_REUSED);
@@ -484,8 +483,9 @@ PHPAPI void _mysqlnd_end_psession(MYSQLND *conn TSRMLS_DC)
/* }}} */
-/* {{{ mysqlnd_connect */
-PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
+/* {{{ mysqlnd_conn::connect */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND *conn,
const char *host, const char *user,
const char *passwd, unsigned int passwd_len,
const char *db, unsigned int db_len,
@@ -505,12 +505,14 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
zend_bool unix_socket = FALSE;
const MYSQLND_CHARSET * charset;
zend_bool reconnect = FALSE;
+ zend_bool saved_compression = FALSE;
php_mysql_packet_greet greet_packet;
php_mysql_packet_auth *auth_packet;
php_mysql_packet_ok ok_packet;
- DBG_ENTER("mysqlnd_connect");
+ DBG_ENTER("mysqlnd_conn::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_GET_STATE(conn):-1);
@@ -531,6 +533,15 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
MYSQLND_DEC_CONN_STATISTIC(&conn->stats, STAT_OPENED_PERSISTENT_CONNECTIONS);
}
/* Now reconnect using the same handle */
+ if (conn->net.compressed) {
+ /*
+ we need to save the state. As we will re-connect, net.compressed should be off, or
+ we will look for a compression header as part of the greet message, but there will
+ be none.
+ */
+ saved_compression = TRUE;
+ conn->net.compressed = FALSE;
+ }
}
if (!host || !host[0]) {
@@ -558,30 +569,25 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
}
transport_len = spprintf(&transport, 0, "unix://%s", socket);
unix_socket = TRUE;
- } else
+ } else
#endif
{
transport_len = spprintf(&transport, 0, "tcp://%s:%d", host, port);
}
- DBG_INF_FMT("transport=%p", transport);
+ DBG_INF_FMT("transport=%s", transport);
PACKET_INIT_ALLOCA(greet_packet, PROT_GREET_PACKET);
PACKET_INIT(auth_packet, PROT_AUTH_PACKET, php_mysql_packet_auth *, FALSE);
PACKET_INIT_ALLOCA(ok_packet, PROT_OK_PACKET);
- if (!conn) {
- conn = mysqlnd_init(FALSE);
- self_alloced = TRUE;
- }
-
if (conn->persistent) {
hashed_details_len = spprintf(&hashed_details, 0, "%p", conn);
DBG_INF_FMT("hashed_details=%s", hashed_details);
- }
+ }
CONN_SET_STATE(conn, CONN_ALLOCED);
- conn->net.packet_no = 0;
+ conn->net.packet_no = conn->net.compressed_envelope_packet_no = 0;
if (conn->options.timeout_connect) {
tv.tv_sec = conn->options.timeout_connect;
@@ -596,7 +602,7 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
conn->scheme_len = strlen(conn->scheme);
DBG_INF(conn->scheme);
conn->net.stream = php_stream_xport_create(conn->scheme, transport_len, streams_options, streams_flags,
- hashed_details,
+ hashed_details,
(conn->options.timeout_connect) ? &tv : NULL,
NULL /*ctx*/, &errstr, &errcode);
DBG_INF_FMT("stream=%p", conn->net.stream);
@@ -651,6 +657,13 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
mysqlnd_set_sock_no_delay(conn->net.stream);
}
+ {
+ unsigned int buf_size;
+ buf_size = MYSQLND_G(net_read_buffer_size); /* this is long, cast to unsigned int*/
+ conn->m->set_client_option(conn, MYSQLND_OPT_NET_READ_BUFFER_SIZE, (char *)&buf_size TSRMLS_CC);
+ }
+
+
if (FAIL == PACKET_READ_ALLOCA(greet_packet, conn)) {
DBG_ERR("Error while reading greeting packet");
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading greeting packet. PID=%d", getpid());
@@ -659,7 +672,7 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
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;
+ 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);
@@ -707,7 +720,7 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
if (!PACKET_WRITE(auth_packet, conn)) {
CONN_SET_STATE(conn, CONN_QUIT_SENT);
SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
- goto err;
+ goto err;
}
if (FAIL == PACKET_READ_ALLOCA(ok_packet, conn) || ok_packet.field_count >= 0xFE) {
@@ -730,6 +743,15 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
}
} else {
CONN_SET_STATE(conn, CONN_READY);
+ if (!self_alloced && saved_compression) {
+ conn->net.compressed = TRUE;
+ }
+ /*
+ If a connect on a existing handle is performed and mysql_flags is
+ passed which doesn't CLIENT_COMPRESS, then we need to overwrite the value
+ which we set based on saved_compression.
+ */
+ conn->net.compressed = mysql_flags & CLIENT_COMPRESS? TRUE:FALSE;
conn->user = pestrdup(user, conn->persistent);
conn->user_len = strlen(conn->user);
@@ -781,19 +803,18 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
buf_size = MYSQLND_G(net_cmd_buffer_size); /* this is long, cast to unsigned int*/
conn->m->set_client_option(conn, MYSQLND_OPT_NET_CMD_BUFFER_SIZE,
- (char *)&buf_size TSRMLS_CC);
+ (char *)&buf_size TSRMLS_CC);
}
MYSQLND_INC_CONN_STATISTIC_W_VALUE2(&conn->stats, STAT_CONNECT_SUCCESS, 1, STAT_OPENED_CONNECTIONS, 1);
if (reconnect) {
- MYSQLND_INC_GLOBAL_STATISTIC(STAT_RECONNECT);
+ MYSQLND_INC_GLOBAL_STATISTIC(STAT_RECONNECT);
}
if (conn->persistent) {
MYSQLND_INC_CONN_STATISTIC_W_VALUE2(&conn->stats, STAT_PCONNECT_SUCCESS, 1, STAT_OPENED_PERSISTENT_CONNECTIONS, 1);
}
DBG_INF_FMT("connection_id=%llu", conn->thread_id);
- conn->result_set_memory_pool = mysqlnd_mempool_create(16000 TSRMLS_CC);
#if PHP_MAJOR_VERSION >= 6
{
unsigned int as_unicode = 1;
@@ -838,7 +859,7 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
PACKET_FREE(auth_packet);
PACKET_FREE_ALLOCA(ok_packet);
- DBG_RETURN(conn);
+ DBG_RETURN(PASS);
}
err:
PACKET_FREE_ALLOCA(greet_packet);
@@ -858,24 +879,56 @@ err:
conn->scheme = NULL;
}
- if (self_alloced) {
- /*
- We have alloced, thus there are no references to this
- object - we are free to kill it!
- */
- conn->m->dtor(conn TSRMLS_CC);
- } else {
- /* This will also close conn->net.stream if it has been opened */
- conn->m->free_contents(conn TSRMLS_CC);
- MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_CONNECT_FAILURE);
+ /* This will also close conn->net.stream if it has been opened */
+ conn->m->free_contents(conn TSRMLS_CC);
+ MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_CONNECT_FAILURE);
+
+ DBG_RETURN(FAIL);
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_connect */
+PHPAPI MYSQLND * mysqlnd_connect(MYSQLND * conn,
+ const char *host, const char *user,
+ const char *passwd, unsigned int passwd_len,
+ const char *db, unsigned int db_len,
+ unsigned int port,
+ const char *socket,
+ unsigned int mysql_flags,
+ MYSQLND_THD_ZVAL_PCACHE *zval_cache
+ TSRMLS_DC)
+{
+ enum_func_status ret;
+ zend_bool self_alloced = FALSE;
+
+ DBG_ENTER("mysqlnd_connect");
+ DBG_INF_FMT("host=%s user=%s db=%s port=%d flags=%d", host?host:"", user?user:"", db?db:"", port, mysql_flags);
+
+ if (!conn) {
+ conn = mysqlnd_init(FALSE);
+ self_alloced = TRUE;
}
- DBG_RETURN(NULL);
+
+ ret = conn->m->connect(conn, host, user, passwd, passwd_len, db, db_len, port, socket, mysql_flags, zval_cache TSRMLS_CC);
+
+ if (ret == FAIL) {
+ if (self_alloced) {
+ /*
+ We have alloced, thus there are no references to this
+ object - we are free to kill it!
+ */
+ conn->m->dtor(conn TSRMLS_CC);
+ }
+ DBG_RETURN(NULL);
+ }
+ DBG_RETURN(conn);
}
/* }}} */
/* {{{ mysqlnd_conn::query */
-/*
+/*
If conn->error_info.error_no is not zero, then we had an error.
Still the result from the query is PASS
*/
@@ -896,7 +949,7 @@ MYSQLND_METHOD(mysqlnd_conn, query)(MYSQLND *conn, const char *query, unsigned i
Here read the result set. We don't do it in simple_command because it need
information from the ok packet. We will fetch it ourselves.
*/
- ret = mysqlnd_query_read_result_set_header(conn, NULL TSRMLS_CC);
+ ret = conn->m->query_read_result_set_header(conn, NULL TSRMLS_CC);
if (ret == PASS && conn->last_query_type == QUERY_UPSERT && conn->upsert_status.affected_rows) {
MYSQLND_INC_CONN_STATISTIC_W_VALUE(&conn->stats, STAT_ROWS_AFFECTED_NORMAL, conn->upsert_status.affected_rows);
}
@@ -932,9 +985,9 @@ MYSQLND_METHOD(mysqlnd_conn, reap_query)(MYSQLND * conn TSRMLS_DC)
if (state <= CONN_READY || state == CONN_QUIT_SENT) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not opened, clear or has been closed");
- DBG_RETURN(FAIL);
+ DBG_RETURN(FAIL);
}
- DBG_RETURN(mysqlnd_query_read_result_set_header(conn, NULL TSRMLS_CC));
+ DBG_RETURN(conn->m->query_read_result_set_header(conn, NULL TSRMLS_CC));
}
/* }}} */
@@ -967,7 +1020,7 @@ MYSQLND ** mysqlnd_stream_array_check_for_readiness(MYSQLND ** conn_array TSRMLS
}
p++;
}
- *ret_p = NULL;
+ *ret_p = NULL;
}
return ret;
}
@@ -988,7 +1041,7 @@ static int mysqlnd_stream_array_to_fd_set(MYSQLND **conn_array, fd_set *fds, php
* */
if (SUCCESS == php_stream_cast((*p)->net.stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL,
(void*)&this_fd, 1) && this_fd >= 0) {
-
+
PHP_SAFE_FD_SET(this_fd, fds);
if (this_fd > *max_fd) {
@@ -1027,7 +1080,7 @@ static int mysqlnd_stream_array_from_fd_set(MYSQLND **conn_array, fd_set *fds TS
fwd++;
}
*bckwd = NULL;/* NULL-terminate the list */
-
+
return ret;
}
@@ -1088,14 +1141,14 @@ _mysqlnd_poll(MYSQLND **r_array, MYSQLND **e_array, MYSQLND ***dont_poll, long s
/* Solaris + BSD do not like microsecond values which are >= 1 sec */
if (usec > 999999) {
tv.tv_sec = sec + (usec / 1000000);
- tv.tv_usec = usec % 1000000;
+ tv.tv_usec = usec % 1000000;
} else {
tv.tv_sec = sec;
tv.tv_usec = usec;
}
tv_p = &tv;
-
+
retval = php_select(max_fd + 1, &rfds, &wfds, &efds, tv_p);
if (retval == -1) {
@@ -1145,7 +1198,7 @@ MYSQLND_METHOD(mysqlnd_conn, list_fields)(MYSQLND *conn, const char *table, cons
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 += wild_len;
*p++ = '\0';
}
@@ -1193,14 +1246,14 @@ MYSQLND_METHOD(mysqlnd_conn, list_method)(MYSQLND *conn, const char *query,
if (achtung_wild) {
show_query_len = spprintf(&show_query, 0, query, par1, achtung_wild);
} else {
- show_query_len = spprintf(&show_query, 0, query, par1);
+ show_query_len = spprintf(&show_query, 0, query, par1);
}
} else {
if (achtung_wild) {
show_query_len = spprintf(&show_query, 0, query, achtung_wild);
} else {
- show_query_len = strlen(show_query = (char *)query);
- }
+ show_query_len = strlen(show_query = (char *)query);
+ }
}
if (PASS == conn->m->query(conn, show_query, show_query_len TSRMLS_CC)) {
@@ -1739,7 +1792,7 @@ MYSQLND_METHOD(mysqlnd_conn, get_server_version)(const MYSQLND * const conn)
minor = strtol(p, &p, 10);
p += 1; /* consume the dot */
patch = strtol(p, &p, 10);
-
+
return (unsigned long)(major * 10000L + (unsigned long)(minor * 100L + patch));
}
/* }}} */
@@ -1775,7 +1828,7 @@ MYSQLND_METHOD(mysqlnd_conn, next_result)(MYSQLND * const conn TSRMLS_DC)
We are sure that there is a result set, since conn->state is set accordingly
in mysqlnd_store_result() or mysqlnd_fetch_row_unbuffered()
*/
- if (FAIL == (ret = mysqlnd_query_read_result_set_header(conn, NULL TSRMLS_CC))) {
+ if (FAIL == (ret = conn->m->query_read_result_set_header(conn, NULL TSRMLS_CC))) {
/*
There can be an error in the middle of a multi-statement, which will cancel the multi-statement.
So there are no more results and we should just return FALSE, error_no has been set
@@ -2192,6 +2245,8 @@ MYSQLND_METHOD(mysqlnd_conn, get_connection_stats)(const MYSQLND * const conn,
MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND * const conn TSRMLS_DC);
MYSQLND_CLASS_METHODS_START(mysqlnd_conn)
+ MYSQLND_METHOD(mysqlnd_conn, connect),
+
MYSQLND_METHOD(mysqlnd_conn, escape_string),
MYSQLND_METHOD(mysqlnd_conn, set_charset),
MYSQLND_METHOD(mysqlnd_conn, query),
@@ -2244,6 +2299,8 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_conn)
MYSQLND_METHOD_PRIVATE(mysqlnd_conn, dtor),
+ mysqlnd_query_read_result_set_header,
+
MYSQLND_METHOD_PRIVATE(mysqlnd_conn, get_reference),
MYSQLND_METHOD_PRIVATE(mysqlnd_conn, free_reference),
MYSQLND_METHOD_PRIVATE(mysqlnd_conn, get_state),
@@ -2254,7 +2311,8 @@ MYSQLND_CLASS_METHODS_END;
/* {{{ mysqlnd_init */
PHPAPI MYSQLND *_mysqlnd_init(zend_bool persistent TSRMLS_DC)
{
- MYSQLND *ret = mnd_pecalloc(1, sizeof(MYSQLND), persistent);
+ size_t alloc_size = sizeof(MYSQLND) + mysqlnd_plugin_count() * sizeof(void *);
+ MYSQLND *ret = mnd_pecalloc(1, alloc_size, persistent);
DBG_ENTER("mysqlnd_init");
DBG_INF_FMT("persistent=%d", persistent);
@@ -2265,6 +2323,9 @@ PHPAPI MYSQLND *_mysqlnd_init(zend_bool persistent TSRMLS_DC)
ret->m = mysqlnd_conn_methods;
ret->m->get_reference(ret TSRMLS_CC);
+ ret->net.stream_read = mysqlnd_read_from_stream;
+ ret->net.stream_write = mysqlnd_stream_write;
+
#ifdef MYSQLND_THREADED
ret->LOCK_state = tsrm_mutex_alloc();
@@ -2305,6 +2366,37 @@ PHPAPI void mysqlnd_conn_set_methods(struct st_mysqlnd_conn_methods *methods)
}
/* }}} */
+
+static unsigned int mysqlnd_plugins_counter = 0;
+
+/* {{{ mysqlnd_plugin_register */
+PHPAPI unsigned int mysqlnd_plugin_register()
+{
+ return mysqlnd_plugins_counter++;
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_plugin_count */
+unsigned int mysqlnd_plugin_count()
+{
+ return mysqlnd_plugins_counter;
+}
+/* }}} */
+
+
+/* {{{ _mysqlnd_plugin_get_plugin_connection_data */
+PHPAPI void ** _mysqlnd_plugin_get_plugin_connection_data(const MYSQLND * conn, unsigned int plugin_id TSRMLS_DC)
+{
+ DBG_ENTER("_mysqlnd_plugin_get_plugin_connection_data");
+ DBG_INF_FMT("plugin_id=%u", plugin_id);
+ if (!conn || plugin_id >= mysqlnd_plugin_count()) {
+ return NULL;
+ }
+ DBG_RETURN((void *)conn + sizeof(MYSQLND) + plugin_id * sizeof(void *));
+}
+/* }}} */
+
/*
* Local variables:
* tab-width: 4
diff --git a/ext/mysqlnd/mysqlnd.h b/ext/mysqlnd/mysqlnd.h
index 9dfea4bbef..274c617f79 100644
--- a/ext/mysqlnd/mysqlnd.h
+++ b/ext/mysqlnd/mysqlnd.h
@@ -41,7 +41,7 @@
minimal.
*/
#if PHP_DEBUG
-#define MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND 1
+//#define MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND 1
#endif
#if PHP_DEBUG && !defined(PHP_WIN32)
@@ -65,6 +65,15 @@
void mysqlnd_library_init(TSRMLS_D);
void mysqlnd_library_end(TSRMLS_D);
+PHPAPI unsigned int mysqlnd_plugin_register();
+unsigned int mysqlnd_plugin_count();
+PHPAPI void ** _mysqlnd_plugin_get_plugin_connection_data(const MYSQLND * conn, unsigned int plugin_id TSRMLS_DC);
+#define mysqlnd_plugin_get_plugin_connection_data(c, p_id) _mysqlnd_plugin_get_plugin_connection_data((c), (p_id) TSRMLS_CC)
+
+PHPAPI void ** _mysqlnd_plugin_get_plugin_result_data(const MYSQLND_RES * result, unsigned int plugin_id TSRMLS_DC);
+#define mysqlnd_plugin_get_plugin_result_data(r, p_id) _mysqlnd_plugin_get_plugin_result_data((r), (p_id) TSRMLS_CC)
+
+
PHPAPI struct st_mysqlnd_conn_methods * mysqlnd_conn_get_methods();
PHPAPI void mysqlnd_conn_set_methods(struct st_mysqlnd_conn_methods *methods);
diff --git a/ext/mysqlnd/mysqlnd_charset.c b/ext/mysqlnd/mysqlnd_charset.c
index 3fc434cc5a..e36cb64df9 100644
--- a/ext/mysqlnd/mysqlnd_charset.c
+++ b/ext/mysqlnd/mysqlnd_charset.c
@@ -171,7 +171,7 @@ static unsigned int check_mb_eucjpms(const char *start, const char *end)
if (valid_eucjpms_ss2(start[0]) && (end - start) > 1 && valid_eucjpms_kata(start[1])) {
return 2;
}
- if (valid_eucjpms_ss3(start[0]) && (end - start) > 2 && valid_eucjpms(start[1]) &&
+ if (valid_eucjpms_ss3(start[0]) && (end - start) > 2 && valid_eucjpms(start[1]) &&
valid_eucjpms(start[2])) {
return 2;
}
@@ -199,7 +199,7 @@ static unsigned int mysqlnd_mbcharlen_eucjpms(unsigned int jpms)
static unsigned int check_mb_gb2312(const char *start, const char *end)
{
- return (valid_gb2312_head((unsigned int)start[0]) && end - start > 1 &&
+ return (valid_gb2312_head((unsigned int)start[0]) && end - start > 1 &&
valid_gb2312_tail((unsigned int)start[1])) ? 2 : 0;
}
@@ -311,7 +311,7 @@ const MYSQLND_CHARSET mysqlnd_charsets[] =
{ 19, "euckr", "euckr_korean_ci", 1, 2, "", mysqlnd_mbcharlen_euckr, check_mb_euckr},
{ 22, "koi8u", "koi8u_general_ci", 1, 1, "", NULL, NULL},
{ 24, "gb2312", "gb2312_chinese_ci", 1, 2, "", mysqlnd_mbcharlen_gb2312, check_mb_gb2312},
- { 25, "greek", "greek_general_ci", 1, 1, "", NULL, NULL},
+ { 25, "greek", "greek_general_ci", 1, 1, "", NULL, NULL},
{ 26, "cp1250", "cp1250_general_ci", 1, 1, "", NULL, NULL},
{ 28, "gbk", "gbk_chinese_ci", 1, 2, "", mysqlnd_mbcharlen_gbk, check_mb_gbk},
{ 30, "latin5", "latin5_turkish_ci", 1, 1, "", NULL, NULL},
@@ -449,7 +449,7 @@ const MYSQLND_CHARSET mysqlnd_charsets60[] =
{ 19, "euckr", "euckr_korean_ci", 1, 2, "", mysqlnd_mbcharlen_euckr, check_mb_euckr},
{ 22, "koi8u", "koi8u_general_ci", 1, 1, "", NULL, NULL},
{ 24, "gb2312", "gb2312_chinese_ci", 1, 2, "", mysqlnd_mbcharlen_gb2312, check_mb_gb2312},
- { 25, "greek", "greek_general_ci", 1, 1, "", NULL, NULL},
+ { 25, "greek", "greek_general_ci", 1, 1, "", NULL, NULL},
{ 26, "cp1250", "cp1250_general_ci", 1, 1, "", NULL, NULL},
{ 28, "gbk", "gbk_chinese_ci", 1, 2, "", mysqlnd_mbcharlen_gbk, check_mb_gbk},
{ 30, "latin5", "latin5_turkish_ci", 1, 1, "", NULL, NULL},
@@ -635,7 +635,7 @@ PHPAPI ulong mysqlnd_cset_escape_quotes(const MYSQLND_CHARSET * const cset, char
for (;escapestr < end; escapestr++) {
unsigned int len = 0;
/* check unicode characters */
-
+
if (cset->char_maxlen > 1 && (len = cset->mb_valid(escapestr, end))) {
/* check possible overflow */
@@ -685,7 +685,8 @@ PHPAPI ulong mysqlnd_cset_escape_slashes(const MYSQLND_CHARSET * const cset, cha
zend_bool escape_overflow = FALSE;
DBG_ENTER("mysqlnd_cset_escape_slashes");
-
+ DBG_INF_FMT("charset=%s", cset->name);
+
for (;escapestr < end; escapestr++) {
char esc = '\0';
unsigned int len = 0;
diff --git a/ext/mysqlnd/mysqlnd_enum_n_def.h b/ext/mysqlnd/mysqlnd_enum_n_def.h
index 9bef37b9ea..1735de5e77 100644
--- a/ext/mysqlnd/mysqlnd_enum_n_def.h
+++ b/ext/mysqlnd/mysqlnd_enum_n_def.h
@@ -31,6 +31,8 @@
#endif
+#define MYSQLND_MIN_COMPRESS_LEN 0
+
#define MYSQLND_MAX_PACKET_SIZE (256L*256L*256L-1)
#define MYSQLND_ERRMSG_SIZE 512
diff --git a/ext/mysqlnd/mysqlnd_loaddata.c b/ext/mysqlnd/mysqlnd_loaddata.c
index f37aff51b3..c050f4019f 100644
--- a/ext/mysqlnd/mysqlnd_loaddata.c
+++ b/ext/mysqlnd/mysqlnd_loaddata.c
@@ -75,7 +75,7 @@ int mysqlnd_local_infile_init(void **ptr, char *filename, void **userdata TSRMLS
if (info->fd == NULL) {
snprintf((char *)info->error_msg, sizeof(info->error_msg), "Can't find file '%-.64s'.", filename);
- info->error_no = MYSQLND_EE_FILENOTFOUND;
+ info->error_no = MYSQLND_EE_FILENOTFOUND;
DBG_RETURN(1);
}
@@ -196,7 +196,7 @@ mysqlnd_handle_local_infile(MYSQLND *conn, const char *filename, zend_bool *is_w
infile = conn->infile;
/* allocate buffer for reading data */
buf = (char *)mnd_ecalloc(1, buflen);
-
+
*is_warning = FALSE;
/* init handler: allocate read buffer and open file */
diff --git a/ext/mysqlnd/mysqlnd_priv.h b/ext/mysqlnd/mysqlnd_priv.h
index 759c91e085..fc99d4e076 100644
--- a/ext/mysqlnd/mysqlnd_priv.h
+++ b/ext/mysqlnd/mysqlnd_priv.h
@@ -42,8 +42,7 @@
#endif
#define MYSQLND_CLASS_METHOD_TABLE_NAME(class) mysqlnd_##class##_methods
-#define MYSQLND_CLASS_METHODS_START(class) static \
- struct st_##class##_methods MYSQLND_CLASS_METHOD_TABLE_NAME(class) = {
+#define MYSQLND_CLASS_METHODS_START(class) struct st_##class##_methods MYSQLND_CLASS_METHOD_TABLE_NAME(class) = {
#define MYSQLND_CLASS_METHODS_END }
#if PHP_MAJOR_VERSION < 6
diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c
index c788fdcd4d..9fc1d5d660 100644
--- a/ext/mysqlnd/mysqlnd_ps.c
+++ b/ext/mysqlnd/mysqlnd_ps.c
@@ -110,10 +110,9 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
result->zval_cache = mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache);
}
- /* Create room for 'next_extend' rows */
+ result->result_set_memory_pool = mysqlnd_mempool_create(16000 TSRMLS_CC);
- ret = mysqlnd_store_result_fetch_data(conn, result, result->meta,
- TRUE, to_cache TSRMLS_CC);
+ ret = result->m.store_result_fetch_data(conn, result, result->meta, TRUE, to_cache TSRMLS_CC);
if (PASS == ret) {
/* libmysql API docs say it should be so for SELECT statements */
@@ -187,8 +186,7 @@ MYSQLND_METHOD(mysqlnd_stmt, background_store_result)(MYSQLND_STMT * const stmt
result->conn = NULL; /* store result does not reference the connection */
}
- ret = mysqlnd_store_result_fetch_data(conn, result, result->meta,
- TRUE, to_cache TSRMLS_CC);
+ ret = result->m.store_result_fetch_data(conn, result, result->meta, TRUE, to_cache TSRMLS_CC);
if (PASS == ret) {
/* libmysql API docs say it should be so for SELECT statements */
@@ -740,7 +738,11 @@ mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param, unsigned int f
current_row,
meta->field_count,
meta->fields,
- result->conn TSRMLS_CC);
+ result->stored_data->persistent,
+ result->conn->options.numeric_and_datetime_as_unicode,
+ result->conn->options.int_and_float_native,
+ result->conn->zval_cache,
+ &result->conn->stats TSRMLS_CC);
if (stmt->update_max_length) {
for (i = 0; i < result->field_count; i++) {
/*
@@ -832,7 +834,7 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
/*
If we skip rows (stmt == NULL || stmt->result_bind == NULL) we have to
- mysqlnd_unbuffered_free_last_data() before it. The function returns always true.
+ result->m.unbuffered_free_last_data() before it. The function returns always true.
*/
if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) {
unsigned int i, field_count = result->field_count;
@@ -840,7 +842,7 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
*fetched_anything = TRUE;
if (!row_packet->skip_extraction) {
- mysqlnd_unbuffered_free_last_data(result TSRMLS_CC);
+ result->m.unbuffered_free_last_data(result TSRMLS_CC);
DBG_INF("extracting data");
result->unbuf->last_row_data = row_packet->fields;
@@ -852,14 +854,18 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
result->unbuf->last_row_data,
row_packet->field_count,
row_packet->fields_metadata,
- result->conn TSRMLS_CC);
+ FALSE,
+ result->conn->options.numeric_and_datetime_as_unicode,
+ result->conn->options.int_and_float_native,
+ result->conn->zval_cache,
+ &result->conn->stats TSRMLS_CC);
for (i = 0; i < field_count; i++) {
if (stmt->result_bind[i].bound == TRUE) {
zval *data = result->unbuf->last_row_data[i];
/*
stmt->result_bind[i].zv has been already destructed
- in mysqlnd_unbuffered_free_last_data()
+ in result->m.unbuffered_free_last_data()
*/
#ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
zval_dtor(stmt->result_bind[i].zv);
@@ -885,7 +891,7 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
} else {
DBG_INF("skipping extraction");
/*
- Data has been allocated and usually mysqlnd_unbuffered_free_last_data()
+ Data has been allocated and usually result->m.unbuffered_free_last_data()
frees it but we can't call this function as it will cause problems with
the bound variables. Thus we need to do part of what it does or Zend will
report leaks.
@@ -1014,7 +1020,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
DBG_INF_FMT("skip_extraction=%d", row_packet->skip_extraction);
if (!row_packet->skip_extraction) {
- mysqlnd_unbuffered_free_last_data(result TSRMLS_CC);
+ result->m.unbuffered_free_last_data(result TSRMLS_CC);
DBG_INF("extracting data");
result->unbuf->last_row_data = row_packet->fields;
@@ -1026,7 +1032,11 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
result->unbuf->last_row_data,
row_packet->field_count,
row_packet->fields_metadata,
- result->conn TSRMLS_CC);
+ FALSE,
+ result->conn->options.numeric_and_datetime_as_unicode,
+ result->conn->options.int_and_float_native,
+ result->conn->zval_cache,
+ &result->conn->stats TSRMLS_CC);
/* If no result bind, do nothing. We consumed the data */
for (i = 0; i < field_count; i++) {
@@ -1034,7 +1044,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
zval *data = result->unbuf->last_row_data[i];
/*
stmt->result_bind[i].zv has been already destructed
- in mysqlnd_unbuffered_free_last_data()
+ in result->m.unbuffered_free_last_data()
*/
#ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
zval_dtor(stmt->result_bind[i].zv);
@@ -1060,7 +1070,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
} else {
DBG_INF("skipping extraction");
/*
- Data has been allocated and usually mysqlnd_unbuffered_free_last_data()
+ Data has been allocated and usually result->m.unbuffered_free_last_data()
frees it but we can't call this function as it will cause problems with
the bound variables. Thus we need to do part of what it does or Zend will
report leaks.
@@ -1708,7 +1718,7 @@ MYSQLND_METHOD(mysqlnd_stmt, result_metadata)(MYSQLND_STMT * const stmt TSRMLS_D
if (stmt->update_max_length && stmt->result->stored_data) {
/* stored result, we have to update the max_length before we clone the meta data :( */
- mysqlnd_res_initialize_result_set_rest(stmt->result TSRMLS_CC);
+ stmt->result->m.initialize_result_set_rest(stmt->result TSRMLS_CC);
}
/*
TODO: This implementation is kind of a hack,
diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c
index 785421e6b2..82b396c674 100644
--- a/ext/mysqlnd/mysqlnd_result.c
+++ b/ext/mysqlnd/mysqlnd_result.c
@@ -22,6 +22,7 @@
#include "php.h"
#include "mysqlnd.h"
#include "mysqlnd_wireprotocol.h"
+#include "mysqlnd_block_alloc.h"
#include "mysqlnd_priv.h"
#include "mysqlnd_result.h"
#include "mysqlnd_result_meta.h"
@@ -92,15 +93,16 @@ void * mysqlnd_fetch_thread(void *arg)
#endif /* MYSQLND_THREADED */
-/* {{{ mysqlnd_res_initialize_result_set_rest */
-void mysqlnd_res_initialize_result_set_rest(MYSQLND_RES * const result TSRMLS_DC)
+/* {{{ mysqlnd_res::initialize_result_set_rest */
+static void
+MYSQLND_METHOD(mysqlnd_res, initialize_result_set_rest)(MYSQLND_RES * const result TSRMLS_DC)
{
unsigned int i;
zval **data_cursor = result->stored_data->data;
zval **data_begin = result->stored_data->data;
unsigned int field_count = result->meta->field_count;
unsigned int row_count = result->stored_data->row_count;
- DBG_ENTER("mysqlnd_res_initialize_result_set_rest");
+ DBG_ENTER("mysqlnd_res::initialize_result_set_rest");
if (!data_cursor || row_count == result->stored_data->initialized_rows) {
DBG_VOID_RETURN;
@@ -113,7 +115,11 @@ void mysqlnd_res_initialize_result_set_rest(MYSQLND_RES * const result TSRMLS_DC
data_cursor,
result->meta->field_count,
result->meta->fields,
- result->conn TSRMLS_CC);
+ result->stored_data->persistent,
+ result->conn->options.numeric_and_datetime_as_unicode,
+ result->conn->options.int_and_float_native,
+ result->conn->zval_cache,
+ &result->conn->stats TSRMLS_CC);
for (i = 0; i < result->field_count; i++) {
/*
NULL fields are 0 length, 0 is not more than 0
@@ -135,12 +141,13 @@ void mysqlnd_res_initialize_result_set_rest(MYSQLND_RES * const result TSRMLS_DC
/* }}} */
-/* {{{ mysqlnd_unbuffered_free_last_data */
-void mysqlnd_unbuffered_free_last_data(MYSQLND_RES *result TSRMLS_DC)
+/* {{{ mysqlnd_res::unbuffered_free_last_data */
+static void
+MYSQLND_METHOD(mysqlnd_res, unbuffered_free_last_data)(MYSQLND_RES * result TSRMLS_DC)
{
MYSQLND_RES_UNBUFFERED *unbuf = result->unbuf;
- DBG_ENTER("mysqlnd_unbuffered_free_last_data");
+ DBG_ENTER("mysqlnd_res::unbuffered_free_last_data");
if (!unbuf) {
DBG_VOID_RETURN;
@@ -186,15 +193,16 @@ void mysqlnd_unbuffered_free_last_data(MYSQLND_RES *result TSRMLS_DC)
/* }}} */
-/* {{{ mysqlnd_free_buffered_data */
-void mysqlnd_free_buffered_data(MYSQLND_RES *result TSRMLS_DC)
+/* {{{ mysqlnd_res::free_buffered_data */
+static void
+MYSQLND_METHOD(mysqlnd_res, free_buffered_data)(MYSQLND_RES *result TSRMLS_DC)
{
MYSQLND_THD_ZVAL_PCACHE *zval_cache = result->zval_cache;
MYSQLND_RES_BUFFERED *set = result->stored_data;
unsigned int field_count = result->field_count;
int row;
- DBG_ENTER("mysqlnd_free_buffered_data");
+ DBG_ENTER("mysqlnd_res::free_buffered_data");
DBG_INF_FMT("Freeing "MYSQLND_LLU_SPEC" row(s)", set->row_count);
DBG_INF_FMT("before: real_usage=%lu usage=%lu", zend_memory_usage(TRUE TSRMLS_CC), zend_memory_usage(FALSE TSRMLS_CC));
@@ -332,11 +340,11 @@ MYSQLND_METHOD(mysqlnd_res, free_result_buffers)(MYSQLND_RES *result TSRMLS_DC)
DBG_INF_FMT("%s", result->unbuf? "unbuffered":(result->stored_data? "buffered":"unknown"));
if (result->unbuf) {
- mysqlnd_unbuffered_free_last_data(result TSRMLS_CC);
+ result->m.unbuffered_free_last_data(result TSRMLS_CC);
mnd_efree(result->unbuf);
result->unbuf = NULL;
} else if (result->stored_data) {
- mysqlnd_free_buffered_data(result TSRMLS_CC);
+ result->m.free_buffered_data(result TSRMLS_CC);
result->stored_data = NULL;
}
#ifdef MYSQLND_THREADED
@@ -357,6 +365,12 @@ MYSQLND_METHOD(mysqlnd_res, free_result_buffers)(MYSQLND_RES *result TSRMLS_DC)
result->row_packet = NULL;
}
+ if (result->result_set_memory_pool) {
+ DBG_INF("Freeing memory pool");
+ mysqlnd_mempool_destroy(result->result_set_memory_pool TSRMLS_CC);
+ result->result_set_memory_pool = NULL;
+ }
+
DBG_VOID_RETURN;
}
/* }}} */
@@ -759,12 +773,12 @@ mysqlnd_fetch_row_unbuffered_c(MYSQLND_RES *result TSRMLS_DC)
/*
If we skip rows (row == NULL) we have to
- mysqlnd_unbuffered_free_last_data() before it. The function returns always true.
+ result->m.unbuffered_free_last_data() before it. The function returns always true.
*/
if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) {
result->unbuf->row_count++;
- mysqlnd_unbuffered_free_last_data(result TSRMLS_CC);
+ result->m.unbuffered_free_last_data(result TSRMLS_CC);
result->unbuf->last_row_data = row_packet->fields;
result->unbuf->last_row_buffer = row_packet->row_buffer;
@@ -781,7 +795,11 @@ mysqlnd_fetch_row_unbuffered_c(MYSQLND_RES *result TSRMLS_DC)
result->unbuf->last_row_data,
row_packet->field_count,
row_packet->fields_metadata,
- result->conn TSRMLS_CC);
+ FALSE,
+ result->conn->options.numeric_and_datetime_as_unicode,
+ result->conn->options.int_and_float_native,
+ result->conn->zval_cache,
+ &result->conn->stats TSRMLS_CC);
retrow = mnd_malloc(result->field_count * sizeof(char *));
@@ -829,7 +847,7 @@ mysqlnd_fetch_row_unbuffered_c(MYSQLND_RES *result TSRMLS_DC)
} else {
CONN_SET_STATE(result->conn, CONN_READY);
}
- mysqlnd_unbuffered_free_last_data(result TSRMLS_CC);
+ result->m.unbuffered_free_last_data(result TSRMLS_CC);
}
DBG_RETURN(retrow);
@@ -864,13 +882,13 @@ mysqlnd_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int flag
/*
If we skip rows (row == NULL) we have to
- mysqlnd_unbuffered_free_last_data() before it. The function returns always true.
+ result->m.unbuffered_free_last_data() before it. The function returns always true.
*/
if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) {
result->unbuf->row_count++;
*fetched_anything = TRUE;
- mysqlnd_unbuffered_free_last_data(result TSRMLS_CC);
+ result->m.unbuffered_free_last_data(result TSRMLS_CC);
result->unbuf->last_row_data = row_packet->fields;
result->unbuf->last_row_buffer = row_packet->row_buffer;
@@ -891,7 +909,11 @@ mysqlnd_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int flag
result->unbuf->last_row_data,
field_count,
row_packet->fields_metadata,
- result->conn TSRMLS_CC);
+ FALSE,
+ result->conn->options.numeric_and_datetime_as_unicode,
+ result->conn->options.int_and_float_native,
+ result->conn->zval_cache,
+ &result->conn->stats TSRMLS_CC);
for (i = 0; i < field_count; i++, field++, zend_hash_key++) {
zval *data = result->unbuf->last_row_data[i];
@@ -962,7 +984,7 @@ mysqlnd_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int flag
} else {
CONN_SET_STATE(result->conn, CONN_READY);
}
- mysqlnd_unbuffered_free_last_data(result TSRMLS_CC);
+ result->m.unbuffered_free_last_data(result TSRMLS_CC);
*fetched_anything = FALSE;
}
@@ -996,6 +1018,8 @@ MYSQLND_METHOD(mysqlnd_res, use_result)(MYSQLND_RES * const result, zend_bool ps
}
result->unbuf = mnd_ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
+ result->result_set_memory_pool = mysqlnd_mempool_create(16000 TSRMLS_CC);
+
/*
Will be freed in the mysqlnd_internal_free_result_contents() called
by the resource destructor. mysqlnd_fetch_row_unbuffered() expects
@@ -1003,6 +1027,7 @@ MYSQLND_METHOD(mysqlnd_res, use_result)(MYSQLND_RES * const result, zend_bool ps
*/
/* FALSE = non-persistent */
PACKET_INIT(result->row_packet, PROT_ROW_PACKET, php_mysql_packet_row *, FALSE);
+ result->row_packet->result_set_memory_pool = result->result_set_memory_pool;
result->row_packet->field_count = result->field_count;
result->row_packet->binary_protocol = ps;
result->row_packet->fields_metadata = result->meta->fields;
@@ -1039,7 +1064,11 @@ mysqlnd_fetch_row_buffered_c(MYSQLND_RES *result TSRMLS_DC)
current_row,
result->meta->field_count,
result->meta->fields,
- result->conn TSRMLS_CC);
+ FALSE,
+ result->conn->options.numeric_and_datetime_as_unicode,
+ result->conn->options.int_and_float_native,
+ result->conn->zval_cache,
+ &result->conn->stats TSRMLS_CC);
for (i = 0; i < result->field_count; i++) {
/*
NULL fields are 0 length, 0 is not more than 0
@@ -1105,7 +1134,11 @@ mysqlnd_fetch_row_buffered(MYSQLND_RES *result, void *param, unsigned int flags,
current_row,
result->meta->field_count,
result->meta->fields,
- result->conn TSRMLS_CC);
+ result->stored_data->persistent,
+ result->conn->options.numeric_and_datetime_as_unicode,
+ result->conn->options.int_and_float_native,
+ result->conn->zval_cache,
+ &result->conn->stats TSRMLS_CC);
for (i = 0; i < result->field_count; i++) {
/*
NULL fields are 0 length, 0 is not more than 0
@@ -1174,19 +1207,19 @@ mysqlnd_fetch_row_buffered(MYSQLND_RES *result, void *param, unsigned int flags,
#define STORE_RESULT_PREALLOCATED_SET_IF_NOT_EMPTY 2
-/* {{{ mysqlnd_store_result_fetch_data */
+/* {{{ mysqlnd_res::store_result_fetch_data */
enum_func_status
-mysqlnd_store_result_fetch_data(MYSQLND * const conn, MYSQLND_RES *result,
- MYSQLND_RES_METADATA *meta,
- zend_bool binary_protocol,
- zend_bool to_cache TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data)(MYSQLND * const conn, MYSQLND_RES *result,
+ MYSQLND_RES_METADATA *meta,
+ zend_bool binary_protocol,
+ zend_bool to_cache TSRMLS_DC)
{
enum_func_status ret;
php_mysql_packet_row *row_packet;
unsigned int next_extend = STORE_RESULT_PREALLOCATED_SET_IF_NOT_EMPTY, free_rows = 1;
MYSQLND_RES_BUFFERED *set;
- DBG_ENTER("mysqlnd_store_result_fetch_data");
+ DBG_ENTER("mysqlnd_res::store_result_fetch_data");
DBG_INF_FMT("conn=%llu binary_proto=%d to_cache=%d",
conn->thread_id, binary_protocol, to_cache);
@@ -1203,6 +1236,7 @@ mysqlnd_store_result_fetch_data(MYSQLND * const conn, MYSQLND_RES *result,
/* non-persistent */
PACKET_INIT(row_packet, PROT_ROW_PACKET, php_mysql_packet_row *, FALSE);
+ row_packet->result_set_memory_pool = result->result_set_memory_pool;
row_packet->field_count = meta->field_count;
row_packet->binary_protocol = binary_protocol;
row_packet->fields_metadata = meta->fields;
@@ -1303,10 +1337,10 @@ MYSQLND_METHOD(mysqlnd_res, store_result)(MYSQLND_RES * result,
CONN_SET_STATE(conn, CONN_FETCHING_DATA);
+ result->result_set_memory_pool = mysqlnd_mempool_create(16000 TSRMLS_CC);
result->lengths = mnd_ecalloc(result->field_count, sizeof(unsigned long));
- ret = mysqlnd_store_result_fetch_data(conn, result, result->meta,
- ps_protocol, to_cache TSRMLS_CC);
+ ret = result->m.store_result_fetch_data(conn, result, result->meta, ps_protocol, to_cache TSRMLS_CC);
if (PASS == ret) {
/* libmysql's documentation says it should be so for SELECT statements */
conn->upsert_status.affected_rows = result->stored_data->row_count;
@@ -1369,7 +1403,10 @@ mysqlnd_fetch_row_async_buffered(MYSQLND_RES *result, void *param, unsigned int
current_row,
result->meta->field_count,
result->meta->fields,
- result->conn TSRMLS_CC);
+ result->conn->options.numeric_and_datetime_as_unicode,
+ result->conn->options.int_and_float_native,
+ result->conn->zval_cache,
+ &result->conn->stats TSRMLS_CC);
for (i = 0; i < result->field_count; i++) {
/*
@@ -1463,6 +1500,7 @@ mysqlnd_background_store_result_fetch_data(MYSQLND_RES *result TSRMLS_DC)
/* persistent */
PACKET_INIT(row_packet, PROT_ROW_PACKET, php_mysql_packet_row *, TRUE);
+ row_packet->result_set_memory_pool = result->result_set_memory_pool;
row_packet->field_count = result->meta->field_count;
row_packet->binary_protocol = result->m.row_decoder == php_mysqlnd_rowp_read_binary_protocol;
row_packet->fields_metadata = result->meta->fields;
@@ -1496,7 +1534,10 @@ mysqlnd_background_store_result_fetch_data(MYSQLND_RES *result TSRMLS_DC)
set->data[set->row_count],
result->meta->field_count,
result->meta->fields,
- result->conn TSRMLS_CC);
+ result->conn->options.numeric_and_datetime_as_unicode,
+ result->conn->options.int_and_float_native,
+ result->conn->zval_cache,
+ &result->conn->stats TSRMLS_CC);
for (i = 0; i < result->field_count; i++) {
/*
@@ -1748,7 +1789,7 @@ MYSQLND_METHOD(mysqlnd_res, fetch_field)(MYSQLND_RES * const result TSRMLS_DC)
if (result->stored_data && (result->stored_data->initialized_rows < result->stored_data->row_count)) {
DBG_INF_FMT("We have decode the whole result set to be able to satisfy this meta request");
/* we have to initialize the rest to get the updated max length */
- mysqlnd_res_initialize_result_set_rest(result TSRMLS_CC);
+ result->m.initialize_result_set_rest(result TSRMLS_CC);
}
DBG_RETURN(result->meta->m->fetch_field(result->meta TSRMLS_CC));
}
@@ -1777,7 +1818,7 @@ MYSQLND_METHOD(mysqlnd_res, fetch_field_direct)(MYSQLND_RES * const result,
if (result->stored_data && (result->stored_data->initialized_rows < result->stored_data->row_count)) {
DBG_INF_FMT("We have decode the whole result set to be able to satisfy this meta request");
/* we have to initialized the rest to get the updated max length */
- mysqlnd_res_initialize_result_set_rest(result TSRMLS_CC);
+ result->m.initialize_result_set_rest(result TSRMLS_CC);
}
DBG_RETURN(result->meta->m->fetch_field_direct(result->meta, fieldnr TSRMLS_CC));
}
@@ -1795,7 +1836,7 @@ MYSQLND_METHOD(mysqlnd_res, fetch_fields)(MYSQLND_RES * const result TSRMLS_DC)
if (result->meta) {
if (result->stored_data && (result->stored_data->initialized_rows < result->stored_data->row_count)) {
/* we have to initialize the rest to get the updated max length */
- mysqlnd_res_initialize_result_set_rest(result TSRMLS_CC);
+ result->m.initialize_result_set_rest(result TSRMLS_CC);
}
DBG_RETURN(result->meta->m->fetch_fields(result->meta TSRMLS_CC));
}
@@ -1978,7 +2019,8 @@ MYSQLND_METHOD(mysqlnd_res, fetch_field_data)(MYSQLND_RES *result, unsigned int
/* {{{ mysqlnd_result_init */
MYSQLND_RES *mysqlnd_result_init(unsigned int field_count, MYSQLND_THD_ZVAL_PCACHE *cache TSRMLS_DC)
{
- MYSQLND_RES *ret = mnd_ecalloc(1, sizeof(MYSQLND_RES));
+ size_t alloc_size = sizeof(MYSQLND_RES) + mysqlnd_plugin_count() * sizeof(void *);
+ MYSQLND_RES *ret = mnd_ecalloc(1, alloc_size);
DBG_ENTER("mysqlnd_result_init");
DBG_INF_FMT("field_count=%u cache=%p", field_count, cache);
@@ -2007,8 +2049,13 @@ MYSQLND_RES *mysqlnd_result_init(unsigned int field_count, MYSQLND_THD_ZVAL_PCAC
ret->m.free_result_buffers = MYSQLND_METHOD(mysqlnd_res, free_result_buffers);
ret->m.free_result_internal = mysqlnd_internal_free_result;
ret->m.free_result_contents = mysqlnd_internal_free_result_contents;
+ ret->m.free_buffered_data = MYSQLND_METHOD(mysqlnd_res, free_buffered_data);
+ ret->m.unbuffered_free_last_data = MYSQLND_METHOD(mysqlnd_res, unbuffered_free_last_data);
ret->m.read_result_metadata = MYSQLND_METHOD(mysqlnd_res, read_result_metadata);
+ ret->m.store_result_fetch_data = MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data);
+ ret->m.initialize_result_set_rest = MYSQLND_METHOD(mysqlnd_res, initialize_result_set_rest);
+
ret->m.fetch_row_normal_buffered = mysqlnd_fetch_row_buffered;
ret->m.fetch_row_normal_unbuffered = mysqlnd_fetch_row_unbuffered;
ret->m.row_decoder = NULL;
@@ -2017,6 +2064,19 @@ MYSQLND_RES *mysqlnd_result_init(unsigned int field_count, MYSQLND_THD_ZVAL_PCAC
}
/* }}} */
+
+/* {{{ _mysqlnd_plugin_get_plugin_result_data */
+PHPAPI void ** _mysqlnd_plugin_get_plugin_result_data(const MYSQLND_RES * result, unsigned int plugin_id TSRMLS_DC)
+{
+ DBG_ENTER("_mysqlnd_plugin_get_plugin_result_data");
+ DBG_INF_FMT("plugin_id=%u", plugin_id);
+ if (!result || plugin_id >= mysqlnd_plugin_count()) {
+ return NULL;
+ }
+ DBG_RETURN((void *)result + sizeof(MYSQLND_RES) + plugin_id * sizeof(void *));
+}
+/* }}} */
+
/*
* Local variables:
* tab-width: 4
diff --git a/ext/mysqlnd/mysqlnd_result.h b/ext/mysqlnd/mysqlnd_result.h
index 981c300dee..8308204a6b 100644
--- a/ext/mysqlnd/mysqlnd_result.h
+++ b/ext/mysqlnd/mysqlnd_result.h
@@ -25,19 +25,8 @@
MYSQLND_RES *mysqlnd_result_init(unsigned int field_count, MYSQLND_THD_ZVAL_PCACHE *cache TSRMLS_DC);
-void mysqlnd_unbuffered_free_last_data(MYSQLND_RES *result TSRMLS_DC);
-
-enum_func_status
-mysqlnd_store_result_fetch_data(MYSQLND * const conn, MYSQLND_RES *result,
- MYSQLND_RES_METADATA *meta,
- zend_bool binary_protocol,
- zend_bool to_cache TSRMLS_DC);
-
enum_func_status mysqlnd_query_read_result_set_header(MYSQLND *conn, MYSQLND_STMT *stmt TSRMLS_DC);
-void mysqlnd_res_initialize_result_set_rest(MYSQLND_RES * const result TSRMLS_DC);
-
-
#ifdef MYSQLND_THREADED
void * mysqlnd_fetch_thread(void *arg);
#endif
diff --git a/ext/mysqlnd/mysqlnd_structs.h b/ext/mysqlnd/mysqlnd_structs.h
index b54ea7fa7a..0763e0148d 100644
--- a/ext/mysqlnd/mysqlnd_structs.h
+++ b/ext/mysqlnd/mysqlnd_structs.h
@@ -48,7 +48,7 @@ struct st_mysqlnd_memory_pool_chunk
uint64_t app;
MYSQLND_MEMORY_POOL *pool;
zend_uchar *ptr;
- unsigned int size;
+ unsigned int size;
void (*resize_chunk)(MYSQLND_MEMORY_POOL_CHUNK * chunk, unsigned int size TSRMLS_DC);
void (*free_chunk)(MYSQLND_MEMORY_POOL_CHUNK * chunk, zend_bool cache_it TSRMLS_DC);
zend_bool from_pool;
@@ -217,23 +217,44 @@ typedef struct st_mysqlnd_stats
} MYSQLND_STATS;
+typedef struct st_mysqlnd_read_buffer {
+ zend_uchar * data;
+ size_t offset;
+ size_t size;
+ size_t len;
+ zend_bool (*is_empty)(struct st_mysqlnd_read_buffer *);
+ void (*read)(struct st_mysqlnd_read_buffer *, size_t count, zend_uchar * dest);
+ size_t (*bytes_left)(struct st_mysqlnd_read_buffer *);
+ void (*free)(struct st_mysqlnd_read_buffer ** TSRMLS_DC);
+} MYSQLND_READ_BUFFER;
+
+
typedef struct st_mysqlnd_net
{
- php_stream *stream;
- /* sequence for simple checking of correct packets */
- zend_uchar packet_no;
+ php_stream *stream;
+ enum_func_status (*stream_read)(MYSQLND * conn, zend_uchar * buffer, size_t count TSRMLS_DC);
+ size_t (*stream_write)(MYSQLND * const conn, const zend_uchar * const buf, size_t count TSRMLS_DC);
+ /* sequence for simple checking of correct packets */
+ zend_uchar packet_no;
+ zend_bool compressed;
+ zend_uchar compressed_envelope_packet_no;
+#ifdef MYSQLND_COMPRESSION_ENABLED
+ MYSQLND_READ_BUFFER * uncompressed_data;
+#endif
#ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
- zend_uchar last_command;
+ zend_uchar last_command;
#endif
-
/* cmd buffer */
MYSQLND_CMD_BUFFER cmd_buffer;
} MYSQLND_NET;
+
+
struct st_mysqlnd_conn_methods
{
+ enum_func_status (*connect)(MYSQLND *conn, const char *host, const char * user, const char * passwd, unsigned int passwd_len, const char * db, unsigned int db_len, unsigned int port, const char * socket, unsigned int mysql_flags, MYSQLND_THD_ZVAL_PCACHE * zval_cache TSRMLS_DC);
ulong (*escape_string)(const MYSQLND * const conn, char *newstr, const char *escapestr, size_t escapestr_len TSRMLS_DC);
enum_func_status (*set_charset)(MYSQLND * const conn, const char * const charset TSRMLS_DC);
enum_func_status (*query)(MYSQLND *conn, const char *query, unsigned int query_len TSRMLS_DC);
@@ -285,6 +306,8 @@ struct st_mysqlnd_conn_methods
enum_func_status (*close)(MYSQLND *conn, enum_connection_close_type close_type TSRMLS_DC);
void (*dtor)(MYSQLND *conn TSRMLS_DC); /* private */
+ enum_func_status (*query_read_result_set_header)(MYSQLND *conn, MYSQLND_STMT *stmt TSRMLS_DC);
+
MYSQLND * (*get_reference)(MYSQLND * const conn TSRMLS_DC);
enum_func_status (*free_reference)(MYSQLND * const conn TSRMLS_DC);
enum mysqlnd_connection_state (*get_state)(MYSQLND * const conn TSRMLS_DC);
@@ -317,13 +340,25 @@ struct st_mysqlnd_res_methods
enum_func_status (*read_result_metadata)(MYSQLND_RES *result, MYSQLND *conn TSRMLS_DC);
unsigned long * (*fetch_lengths)(MYSQLND_RES * const result);
+ enum_func_status (*store_result_fetch_data)(MYSQLND * const conn, MYSQLND_RES *result, MYSQLND_RES_METADATA *meta, zend_bool binary_protocol, zend_bool to_cache TSRMLS_DC);
+ void (*initialize_result_set_rest)(MYSQLND_RES * const result TSRMLS_DC);
+
void (*free_result_buffers)(MYSQLND_RES * result TSRMLS_DC); /* private */
enum_func_status (*free_result)(MYSQLND_RES * result, zend_bool implicit TSRMLS_DC);
- void (*free_result_internal)(MYSQLND_RES *result TSRMLS_DC);
- void (*free_result_contents)(MYSQLND_RES *result TSRMLS_DC);
+ void (*free_result_internal)(MYSQLND_RES *result TSRMLS_DC);
+ void (*free_result_contents)(MYSQLND_RES *result TSRMLS_DC);
+ void (*free_buffered_data)(MYSQLND_RES *result TSRMLS_DC);
+ void (*unbuffered_free_last_data)(MYSQLND_RES *result TSRMLS_DC);
+
+ /* for decoding - binary or text protocol */
+ void (*row_decoder)(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
+ unsigned int field_count, MYSQLND_FIELD *fields_metadata,
+ zend_bool persistent,
+ zend_bool as_unicode, zend_bool as_int_or_float,
+ MYSQLND_THD_ZVAL_PCACHE * zval_cache,
+ MYSQLND_STATS * stats TSRMLS_DC);
+
- /* for decoding - binary or text protocol */
- void (*row_decoder)(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields, unsigned int field_count, MYSQLND_FIELD *fields_metadata, MYSQLND *conn TSRMLS_DC);
};
@@ -445,7 +480,7 @@ struct st_mysqlnd_connection
/* Temporal storage for mysql_query */
unsigned int field_count;
-
+
/* persistent connection */
zend_bool persistent;
@@ -458,8 +493,6 @@ struct st_mysqlnd_connection
/* qcache */
MYSQLND_QCACHE *qcache;
- MYSQLND_MEMORY_POOL * result_set_memory_pool;
-
/* stats */
MYSQLND_STATS stats;
@@ -490,7 +523,7 @@ struct mysqlnd_field_hash_key
#if PHP_MAJOR_VERSION >= 6
zstr ustr;
unsigned int ulen;
-#endif
+#endif
};
@@ -578,7 +611,7 @@ struct st_mysqlnd_res
/*
Column lengths of current row - both buffered and unbuffered.
- For buffered results it duplicates the data found in **data
+ For buffered results it duplicates the data found in **data
*/
unsigned long *lengths;
@@ -586,6 +619,8 @@ struct st_mysqlnd_res
/* zval cache */
MYSQLND_THD_ZVAL_PCACHE *zval_cache;
+
+ MYSQLND_MEMORY_POOL * result_set_memory_pool;
};
diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c
index ea77bdc0bf..77719f69a9 100644
--- a/ext/mysqlnd/mysqlnd_wireprotocol.c
+++ b/ext/mysqlnd/mysqlnd_wireprotocol.c
@@ -1,3 +1,4 @@
+
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
@@ -29,6 +30,9 @@
#include "ext/standard/sha1.h"
#include "php_network.h"
#include "zend_ini.h"
+#ifdef MYSQLND_COMPRESSION_ENABLED
+#include <zlib.h>
+#endif
#ifndef PHP_WIN32
#include <netinet/tcp.h>
@@ -36,16 +40,14 @@
#include <winsock.h>
#endif
-#define USE_CORK 0
-
#define MYSQLND_SILENT 1
-#define MYSQLND_DUMP_HEADER_N_BODY2
-#define MYSQLND_DUMP_HEADER_N_BODY_FULL2
+#define MYSQLND_DUMP_HEADER_N_BODY
#define PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_size, packet_type_as_text, packet_type) \
{ \
+ DBG_INF_FMT("buf=%p size=%u", (buf), (buf_size)); \
if (FAIL == mysqlnd_read_header((conn), &((packet)->header) TSRMLS_CC)) {\
CONN_SET_STATE(conn, CONN_QUIT_SENT); \
SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);\
@@ -54,15 +56,15 @@
DBG_RETURN(FAIL);\
}\
if ((buf_size) < (packet)->header.size) { \
- DBG_ERR_FMT("Packet buffer wasn't big enough %u bytes will be unread", \
- (packet)->header.size - (buf_size)); \
+ DBG_ERR_FMT("Packet buffer %u wasn't big enough %u, %u bytes will be unread", \
+ (buf_size), (packet)->header.size, (packet)->header.size - (buf_size)); \
+ DBG_RETURN(FAIL); \
}\
- if (!mysqlnd_read_body((conn), (buf), \
- MIN((buf_size), (packet)->header.size) TSRMLS_CC)) { \
+ if (FAIL == mysqlnd_read_body((conn), &((packet)->header), (buf) TSRMLS_CC)) { \
CONN_SET_STATE(conn, CONN_QUIT_SENT); \
SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);\
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", mysqlnd_server_gone); \
- DBG_ERR_FMT("Empty %s packet body", (packet_type_as_text)); \
+ DBG_ERR_FMT("Empty '%s' packet body", (packet_type_as_text)); \
DBG_RETURN(FAIL);\
} \
MYSQLND_INC_CONN_STATISTIC_W_VALUE2(&conn->stats, packet_type_to_statistic_byte_count[packet_type], \
@@ -83,7 +85,7 @@ char * mysqlnd_read_header_name = "mysqlnd_read_header";
char * mysqlnd_read_body_name = "mysqlnd_read_body";
-/* {{{ mysqlnd_command_to_text
+/* {{{ mysqlnd_command_to_text
*/
const char * const mysqlnd_command_to_text[COM_END] =
{
@@ -128,7 +130,7 @@ static enum_mysqlnd_collected_stats packet_type_to_statistic_packet_count[PROT_L
};
-/* {{{ php_mysqlnd_net_field_length
+/* {{{ php_mysqlnd_net_field_length
Get next field's length */
unsigned long php_mysqlnd_net_field_length(zend_uchar **packet)
{
@@ -157,7 +159,7 @@ unsigned long php_mysqlnd_net_field_length(zend_uchar **packet)
/* }}} */
-/* {{{ php_mysqlnd_net_field_length_ll
+/* {{{ php_mysqlnd_net_field_length_ll
Get next field's length */
uint64_t php_mysqlnd_net_field_length_ll(zend_uchar **packet)
{
@@ -212,6 +214,72 @@ zend_uchar *php_mysqlnd_net_store_length(zend_uchar *packet, uint64_t length)
/* }}} */
+#ifdef MYSQLND_COMPRESSION_ENABLED
+/* {{{ php_mysqlnd_read_buffer_is_empty */
+static zend_bool
+php_mysqlnd_read_buffer_is_empty(MYSQLND_READ_BUFFER * buffer)
+{
+ return buffer->len? FALSE:TRUE;
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_read_buffer_read */
+static void
+php_mysqlnd_read_buffer_read(MYSQLND_READ_BUFFER * buffer, size_t count, zend_uchar * dest)
+{
+ if (buffer->len >= count) {
+ memcpy(dest, buffer->data + buffer->offset, count);
+ buffer->offset += count;
+ buffer->len -= count;
+ }
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_read_buffer_bytes_left */
+static size_t
+php_mysqlnd_read_buffer_bytes_left(MYSQLND_READ_BUFFER * buffer)
+{
+ return buffer->len;
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_read_buffer_free */
+static void
+php_mysqlnd_read_buffer_free(MYSQLND_READ_BUFFER ** buffer TSRMLS_DC)
+{
+ DBG_ENTER("php_mysqlnd_read_buffer_free");
+ if (*buffer) {
+ mnd_efree((*buffer)->data);
+ mnd_efree(*buffer);
+ *buffer = NULL;
+ }
+ DBG_VOID_RETURN;
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_create_read_buffer */
+static MYSQLND_READ_BUFFER *
+mysqlnd_create_read_buffer(size_t count TSRMLS_DC)
+{
+ MYSQLND_READ_BUFFER * ret = mnd_emalloc(sizeof(MYSQLND_READ_BUFFER));
+ DBG_ENTER("mysqlnd_create_read_buffer");
+ ret->is_empty = php_mysqlnd_read_buffer_is_empty;
+ ret->read = php_mysqlnd_read_buffer_read;
+ ret->bytes_left = php_mysqlnd_read_buffer_bytes_left;
+ ret->free = php_mysqlnd_read_buffer_free;
+ ret->data = mnd_emalloc(count);
+ ret->size = ret->len = count;
+ ret->offset = 0;
+ DBG_RETURN(ret);
+}
+/* }}} */
+#endif
+
+
/* {{{ php_mysqlnd_consume_uneaten_data */
#ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
size_t php_mysqlnd_consume_uneaten_data(MYSQLND * const conn, enum php_mysqlnd_server_command cmd TSRMLS_DC)
@@ -261,10 +329,10 @@ size_t php_mysqlnd_consume_uneaten_data(MYSQLND * const conn, enum php_mysqlnd_s
/* {{{ php_mysqlnd_read_error_from_line */
-static
-enum_func_status php_mysqlnd_read_error_from_line(zend_uchar *buf, size_t buf_len,
- char *error, int error_buf_len,
- unsigned int *error_no, char *sqlstate TSRMLS_DC)
+static enum_func_status
+php_mysqlnd_read_error_from_line(zend_uchar *buf, size_t buf_len,
+ char *error, int error_buf_len,
+ unsigned int *error_no, char *sqlstate TSRMLS_DC)
{
zend_uchar *p = buf;
int error_msg_len= 0;
@@ -288,9 +356,9 @@ enum_func_status php_mysqlnd_read_error_from_line(zend_uchar *buf, size_t buf_le
}
sqlstate[MYSQLND_SQLSTATE_LENGTH] = '\0';
error[error_msg_len]= '\0';
-
+
DBG_RETURN(FAIL);
-}
+}
/* }}} */
@@ -315,6 +383,17 @@ int mysqlnd_set_sock_no_delay(php_stream *stream)
/* }}} */
+/* {{{ mysqlnd_stream_write */
+size_t mysqlnd_stream_write(MYSQLND * const conn, const zend_uchar * const buf, size_t count TSRMLS_DC)
+{
+ size_t ret;
+ DBG_ENTER("mysqlnd_stream_write");
+ ret = php_stream_write(conn->net.stream, (char *)buf, count);
+ DBG_RETURN(ret);
+}
+/* }}} */
+
+
/* We assume that MYSQLND_HEADER_SIZE is 4 bytes !! */
#define STORE_HEADER_SIZE(safe_storage, buffer) int4store((safe_storage), (*(uint32_t *)(buffer)))
#define RESTORE_HEADER_SIZE(buffer, safe_storage) STORE_HEADER_SIZE((safe_storage), (buffer))
@@ -338,32 +417,146 @@ size_t mysqlnd_stream_write_w_header(MYSQLND * const conn, char * const buf, siz
size_t old_chunk_size = net->stream->chunk_size;
size_t ret, left = count, packets_sent = 1;
zend_uchar *p = (zend_uchar *) buf;
+ zend_uchar * compress_buf = NULL;
+ size_t comp_buf_size = 0;
DBG_ENTER("mysqlnd_stream_write_w_header");
- DBG_INF_FMT("conn=%llu count=%lu", conn->thread_id, count);
+ DBG_INF_FMT("conn=%llu count=%lu compression=%d", conn->thread_id, count, net->compressed);
net->stream->chunk_size = MYSQLND_MAX_PACKET_SIZE;
+ if (net->compressed == TRUE) {
+ comp_buf_size = MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE + MIN(left, MYSQLND_MAX_PACKET_SIZE);
+ DBG_INF_FMT("compress_buf_size=%d", comp_buf_size);
+ compress_buf = emalloc(comp_buf_size);
+ }
+
while (left > MYSQLND_MAX_PACKET_SIZE) {
- STORE_HEADER_SIZE(safe_storage, p);
- int3store(p, MYSQLND_MAX_PACKET_SIZE);
- int1store(p + 3, net->packet_no);
+#ifdef MYSQLND_COMPRESSION_ENABLED
+
+ if (net->compressed == TRUE) {
+
+ /* here we need to compress the data and then write it, first comes the compressed header */
+ uLong tmp_complen = MYSQLND_MAX_PACKET_SIZE;
+ size_t payload_size;
+ zend_uchar * uncompressed_payload = p; /* should include the header */
+ int res;
+
+ STORE_HEADER_SIZE(safe_storage, uncompressed_payload);
+ int3store(uncompressed_payload, MYSQLND_MAX_PACKET_SIZE);
+ int1store(uncompressed_payload + 3, net->packet_no);
+
+ DBG_INF_FMT("compress(%p, %p, %p, %d)", (compress_buf + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE), &tmp_complen, p, MYSQLND_MAX_PACKET_SIZE + MYSQLND_HEADER_SIZE);
+ res = compress((compress_buf + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE), &tmp_complen, uncompressed_payload, MYSQLND_MAX_PACKET_SIZE + MYSQLND_HEADER_SIZE);
+ if (res == Z_OK) {
+ DBG_INF_FMT("compression successful. compressed size=%d", tmp_complen);
+ int3store(compress_buf + MYSQLND_HEADER_SIZE, MYSQLND_MAX_PACKET_SIZE + MYSQLND_HEADER_SIZE);
+ payload_size = tmp_complen;
+ } else {
+ DBG_INF_FMT("compression NOT successful. error=%d Z_OK=%d Z_BUF_ERROR=%d Z_MEM_ERROR=%d", res, Z_OK, Z_BUF_ERROR, Z_MEM_ERROR);
+ int3store(compress_buf + MYSQLND_HEADER_SIZE, 0);
+ memcpy(compress_buf + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, uncompressed_payload, MYSQLND_MAX_PACKET_SIZE + MYSQLND_HEADER_SIZE);
+ payload_size = MYSQLND_MAX_PACKET_SIZE + MYSQLND_HEADER_SIZE;
+ }
+ RESTORE_HEADER_SIZE(uncompressed_payload, safe_storage);
+
+ int3store(compress_buf, payload_size);
+ int1store(compress_buf + 3, net->packet_no);
+ DBG_INF_FMT("writing %d bytes to the network", payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE);
+ ret = conn->net.stream_write(conn, compress_buf, payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE TSRMLS_CC);
+ net->compressed_envelope_packet_no++;
+ } else
+#endif /* MYSQLND_COMPRESSION_ENABLED */
+ {
+ DBG_INF("no compression");
+ STORE_HEADER_SIZE(safe_storage, p);
+ int3store(p, MYSQLND_MAX_PACKET_SIZE);
+ int1store(p + 3, net->packet_no);
+ ret = conn->net.stream_write(conn, p, MYSQLND_MAX_PACKET_SIZE + MYSQLND_HEADER_SIZE TSRMLS_CC);
+ RESTORE_HEADER_SIZE(p, safe_storage);
+ net->compressed_envelope_packet_no++;
+ }
net->packet_no++;
- ret = php_stream_write(net->stream, (char *)p, MYSQLND_MAX_PACKET_SIZE + MYSQLND_HEADER_SIZE);
- RESTORE_HEADER_SIZE(p, safe_storage);
p += MYSQLND_MAX_PACKET_SIZE;
left -= MYSQLND_MAX_PACKET_SIZE;
packets_sent++;
}
+
+ DBG_INF_FMT("packet_size=%d packet_no=%d", left, net->packet_no);
/* Even for zero size payload we have to send a packet */
- STORE_HEADER_SIZE(safe_storage, p);
- int3store(p, left);
- int1store(p + 3, net->packet_no);
+
+#ifdef MYSQLND_COMPRESSION_ENABLED
+ if (net->compressed == TRUE) {
+ /* here we need to compress the data and then write it, first comes the compressed header */
+ uLong tmp_complen = left;
+ size_t payload_size;
+ zend_uchar * uncompressed_payload = p; /* should include the header */
+ int res = Z_BUF_ERROR;
+
+ STORE_HEADER_SIZE(safe_storage, uncompressed_payload);
+ int3store(uncompressed_payload, left);
+ int1store(uncompressed_payload + 3, net->packet_no);
+ if ((left + MYSQLND_HEADER_SIZE) > MYSQLND_MIN_COMPRESS_LEN) {
+ DBG_INF_FMT("compress(%p, %p, %p, %d)", (compress_buf + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE), &tmp_complen, p, left + MYSQLND_HEADER_SIZE);
+ res = compress((compress_buf + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE), &tmp_complen, uncompressed_payload, left + MYSQLND_HEADER_SIZE);
+ if (res == Z_OK) {
+ DBG_INF_FMT("compression successful. compressed size=%d", tmp_complen);
+ int3store(compress_buf + MYSQLND_HEADER_SIZE, left + MYSQLND_HEADER_SIZE);
+ payload_size = tmp_complen;
+ }
+ } else {
+ DBG_INF("Too short for compression");
+ }
+ if (res != Z_OK) {
+ DBG_INF_FMT("compression NOT successful. error=%d Z_OK=%d Z_BUF_ERROR=%d Z_MEM_ERROR=%d", res, Z_OK, Z_BUF_ERROR, Z_MEM_ERROR);
+ int3store(compress_buf + MYSQLND_HEADER_SIZE, 0);
+ memcpy(compress_buf + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, uncompressed_payload, left + MYSQLND_HEADER_SIZE);
+ payload_size = left + MYSQLND_HEADER_SIZE;
+ }
+ RESTORE_HEADER_SIZE(uncompressed_payload, safe_storage);
+
+ int3store(compress_buf, payload_size);
+ int1store(compress_buf + 3, net->packet_no);
+ DBG_INF_FMT("writing %d bytes to the network", payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE);
+ ret = conn->net.stream_write(conn, compress_buf, payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE TSRMLS_CC);
+
+ net->compressed_envelope_packet_no++;
+ #if WHEN_WE_NEED_TO_CHECK_WHETHER_COMPRESSION_WORKS_CORRECTLY
+ if (res == Z_OK) {
+ size_t decompressed_size = left + MYSQLND_HEADER_SIZE;
+ uLongf tmp_complen2 = decompressed_size;
+ zend_uchar * decompressed_data = malloc(decompressed_size);
+ int error = uncompress(decompressed_data, &tmp_complen2, compress_buf + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, payload_size);
+ if (error == Z_OK) {
+ int i;
+ DBG_INF("success decompressing");
+ for (i = 0 ; i < decompressed_size; i++) {
+ if (i && (i % 30 == 0)) {
+ printf("\n\t\t");
+ }
+ printf("%.2X ", (int)*((char*)&(decompressed_data[i])));
+ DBG_INF_FMT("%.2X ", (int)*((char*)&(decompressed_data[i])));
+ }
+ } else {
+ DBG_INF("error decompressing");
+ }
+ free(decompressed_data);
+ }
+ #endif /* WHEN_WE_NEED_TO_CHECK_WHETHER_COMPRESSION_WORKS_CORRECTLY */
+
+ } else
+#endif /* MYSQLND_COMPRESSION_ENABLED */
+ {
+ DBG_INF("no compression");
+ STORE_HEADER_SIZE(safe_storage, p);
+ int3store(p, left);
+ int1store(p + 3, net->packet_no);
+ ret = conn->net.stream_write(conn, p, left + MYSQLND_HEADER_SIZE TSRMLS_CC);
+ RESTORE_HEADER_SIZE(p, safe_storage);
+ }
net->packet_no++;
- ret = php_stream_write(net->stream, (char *)p, left + MYSQLND_HEADER_SIZE);
- RESTORE_HEADER_SIZE(p, safe_storage);
if (!ret) {
DBG_ERR_FMT("Can't %u send bytes", count);
@@ -377,126 +570,198 @@ size_t mysqlnd_stream_write_w_header(MYSQLND * const conn, char * const buf, siz
STAT_PACKETS_SENT, packets_sent);
net->stream->chunk_size = old_chunk_size;
-
+ if (compress_buf) {
+ efree(compress_buf);
+ }
DBG_RETURN(ret);
}
/* }}} */
-/* {{{ mysqlnd_stream_write_w_command */
-#if USE_CORK && defined(TCP_CORK)
-static
-size_t mysqlnd_stream_write_w_command(MYSQLND * const conn, enum php_mysqlnd_server_command command,
- const char * const buf, size_t count TSRMLS_DC)
+/* {{{ mysqlnd_read_from_stream */
+enum_func_status
+mysqlnd_read_from_stream(MYSQLND * conn, zend_uchar * buffer, size_t count TSRMLS_DC)
{
- zend_uchar safe_buf[((MYSQLND_HEADER_SIZE) + (sizeof(zend_uchar)) - 1) / (sizeof(zend_uchar))];
- zend_uchar *safe_storage = (char *) &safe_buf;
- MYSQLND_NET *net = &conn->net;
- size_t old_chunk_size = net->stream->chunk_size;
- size_t ret, left = count, header_len = MYSQLND_HEADER_SIZE + 1, packets_sent = 1;
- const zend_uchar *p = (zend_uchar *) buf;
- zend_bool command_sent = FALSE;
- int corked = 1;
+ size_t to_read = count, ret;
+ size_t old_chunk_size = conn->net.stream->chunk_size;
+ DBG_ENTER("mysqlnd_read_from_stream");
+ DBG_INF_FMT("count=%u", count);
+ conn->net.stream->chunk_size = MIN(to_read, conn->options.net_read_buffer_size);
+ while (to_read) {
+ if (!(ret = php_stream_read(conn->net.stream, (char *) buffer, to_read))) {
+ DBG_ERR_FMT("Error while reading header from socket");
+ DBG_RETURN(FAIL);
+ }
+ buffer += ret;
+ to_read -= ret;
+ }
+ MYSQLND_INC_CONN_STATISTIC_W_VALUE(&conn->stats, STAT_BYTES_RECEIVED, count);
+ conn->net.stream->chunk_size = old_chunk_size;
+ DBG_RETURN(PASS);
+}
+/* }}} */
- DBG_ENTER("mysqlnd_stream_write_w_command");
- net->stream->chunk_size = MYSQLND_MAX_PACKET_SIZE;
+#ifdef MYSQLND_COMPRESSION_ENABLED
+/* {{{ mysqlnd_read_compressed_packet_from_stream_and_fill_read_buffer */
+static enum_func_status
+mysqlnd_read_compressed_packet_from_stream_and_fill_read_buffer(MYSQLND * conn, size_t net_payload_size TSRMLS_DC)
+{
+ MYSQLND_NET * net = &conn->net;
+ size_t decompressed_size;
+ enum_func_status ret = PASS;
+ zend_uchar * compressed_data = NULL;
+ zend_uchar comp_header[COMPRESSED_HEADER_SIZE];
+ DBG_ENTER("mysqlnd_read_compressed_packet_from_stream_and_fill_read_buffer");
- setsockopt(((php_netstream_data_t*)net->stream->abstract)->socket,
- IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
+ /* Read the compressed header */
+ if (FAIL == conn->net.stream_read(conn, comp_header, COMPRESSED_HEADER_SIZE TSRMLS_CC)) {
+ DBG_RETURN(FAIL);
+ }
+ decompressed_size = uint3korr(comp_header);
- int1store(safe_storage + MYSQLND_HEADER_SIZE, command);
- while (left > MYSQLND_MAX_PACKET_SIZE) {
- size_t body_size = MYSQLND_MAX_PACKET_SIZE;
+ /* When decompressed_size is 0, then the data is not compressed, and we have wasted 3 bytes */
+ /* we need to decompress the data */
- int3store(safe_storage, MYSQLND_MAX_PACKET_SIZE);
- int1store(safe_storage + 3, net->packet_no);
- net->packet_no++;
-
- ret = php_stream_write(net->stream, (char *)safe_storage, header_len);
- if (command_sent == FALSE) {
- --header_len;
- /* Sent one byte less*/
- --body_size;
- command_sent = TRUE;
+ if (decompressed_size) {
+ int error;
+ uLongf tmp_complen = decompressed_size;
+ compressed_data = emalloc(net_payload_size);
+ if (FAIL == conn->net.stream_read(conn, compressed_data, net_payload_size TSRMLS_CC)) {
+ ret = FAIL;
+ goto end;
}
- ret = php_stream_write(net->stream, (char *)p, body_size);
-
- p += body_size;
- left -= body_size;
+ net->uncompressed_data = mysqlnd_create_read_buffer(decompressed_size TSRMLS_CC);
+ error = uncompress(net->uncompressed_data->data, &tmp_complen, compressed_data, net_payload_size);
- packets_sent++;
+ DBG_INF_FMT("compressed data: decomp_len=%d compressed_size=%d", decompressed_size, net_payload_size);
+ if (error != Z_OK) {
+ DBG_ERR_FMT("Can't uncompress packet, error: %d", error);
+ ret = FAIL;
+ goto end;
+ }
+ } else {
+ DBG_INF_FMT("The server decided not to compress the data. Our job is easy. Copying %u bytes", net_payload_size);
+ net->uncompressed_data = mysqlnd_create_read_buffer(net_payload_size TSRMLS_CC);
+ if (FAIL == conn->net.stream_read(conn, net->uncompressed_data->data, net_payload_size TSRMLS_CC)) {
+ ret = FAIL;
+ goto end;
+ }
}
- /* Even for zero size payload we have to send a packet */
- int3store(safe_storage, header_len == MYSQLND_HEADER_SIZE? left:left+1);
- int1store(safe_storage + 3, net->packet_no);
- net->packet_no++;
-
- ret = php_stream_write(net->stream, (char *)safe_storage, header_len);
-
- if (left) {
- ret = php_stream_write(net->stream, (char *)p, left);
+end:
+ if (compressed_data) {
+ efree(compressed_data);
}
- corked = 0;
- setsockopt(((php_netstream_data_t*)net->stream->abstract)->socket,
- IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
+ DBG_RETURN(ret);
+}
+#endif /* MYSQLND_COMPRESSION_ENABLED */
- MYSQLND_INC_CONN_STATISTIC_W_VALUE3(&conn->stats, STAT_BYTES_SENT,
- count + packets_sent * MYSQLND_HEADER_SIZE);
- STAT_PROTOCOL_OVERHEAD_OUT, packets_sent * MYSQLND_HEADER_SIZE);
- STAT_PACKETS_SENT, packets_sent);
- net->stream->chunk_size = old_chunk_size;
+/* {{{ mysqlnd_real_read */
+static enum_func_status
+mysqlnd_real_read(MYSQLND * conn, zend_uchar * buffer, size_t count TSRMLS_DC)
+{
+ size_t to_read = count;
+ zend_uchar * p = buffer;
+
+ DBG_ENTER("mysqlnd_real_read");
+#ifdef MYSQLND_COMPRESSION_ENABLED
+ if (conn->net.compressed) {
+ MYSQLND_NET * net = &conn->net;
+ if (net->uncompressed_data) {
+ size_t to_read_from_buffer = MIN(net->uncompressed_data->bytes_left(net->uncompressed_data), to_read);
+ DBG_INF_FMT("reading %u from uncompressed_data buffer", to_read_from_buffer);
+ if (to_read_from_buffer) {
+ net->uncompressed_data->read(net->uncompressed_data, to_read_from_buffer, (zend_uchar *) p);
+ p += to_read_from_buffer;
+ to_read -= to_read_from_buffer;
+ }
+ DBG_INF_FMT("left %u to read", to_read);
+ if (TRUE == net->uncompressed_data->is_empty(net->uncompressed_data)) {
+ /* Everything was consumed. This should never happen here, but for security */
+ net->uncompressed_data->free(&net->uncompressed_data TSRMLS_CC);
+ }
+ }
+ if (to_read) {
+ zend_uchar net_header[MYSQLND_HEADER_SIZE];
+ size_t net_payload_size;
+ zend_uchar packet_no;
- DBG_RETURN(ret);
-}
+ if (FAIL == conn->net.stream_read(conn, net_header, MYSQLND_HEADER_SIZE TSRMLS_CC)) {
+ DBG_RETURN(FAIL);
+ }
+ net_payload_size = uint3korr(net_header);
+ packet_no = uint1korr(net_header + 3);
+ if (net->compressed_envelope_packet_no != packet_no) {
+ DBG_ERR_FMT("Transport level: packets out of order. Expected %d received %d. Packet size=%d",
+ net->compressed_envelope_packet_no, packet_no, net_payload_size);
+
+ php_error(E_WARNING, "Packets out of order. Expected %d received %d. Packet size="MYSQLND_SZ_T_SPEC,
+ net->compressed_envelope_packet_no, packet_no, net_payload_size);
+#if 0
+ *(int *) NULL = 0;
#endif
+ DBG_RETURN(FAIL);
+ }
+ net->compressed_envelope_packet_no++;
+#ifdef MYSQLND_DUMP_HEADER_N_BODY
+ DBG_INF_FMT("HEADER: hwd_packet_no=%d size=%3d", packet_no, net_payload_size);
+#endif
+ /* Now let's read from the wire, decompress it and fill the read buffer */
+ mysqlnd_read_compressed_packet_from_stream_and_fill_read_buffer(conn, net_payload_size TSRMLS_CC);
+
+ /*
+ Now a bit of recursion - read from the read buffer,
+ if the data which we have just read from the wire
+ is not enough, then the recursive call will try to
+ satisfy it until it is satisfied.
+ */
+ DBG_RETURN(mysqlnd_real_read(conn, p, to_read TSRMLS_CC));
+ }
+ DBG_RETURN(PASS);
+ }
+#endif /* MYSQLND_COMPRESSION_ENABLED */
+ DBG_RETURN(conn->net.stream_read(conn, p, to_read TSRMLS_CC));
+}
/* }}} */
/* {{{ mysqlnd_read_header */
static enum_func_status
-mysqlnd_read_header(MYSQLND *conn, mysqlnd_packet_header *header TSRMLS_DC)
+mysqlnd_read_header(MYSQLND * conn, mysqlnd_packet_header * header TSRMLS_DC)
{
MYSQLND_NET *net = &conn->net;
- char buffer[MYSQLND_HEADER_SIZE];
- char *p = buffer;
- int to_read = MYSQLND_HEADER_SIZE, ret;
-
- DBG_ENTER(mysqlnd_read_header_name);
+ zend_uchar buffer[MYSQLND_HEADER_SIZE];
- do {
- if (!(ret= php_stream_read(net->stream, p, to_read))) {
- DBG_ERR_FMT("Error while reading header from socket");
- return FAIL;
- }
- p += ret;
- to_read -= ret;
- } while (to_read);
+ DBG_ENTER("mysqlnd_read_header_name");
+ DBG_INF_FMT("compressed=%d conn_id=%u", net->compressed, conn->thread_id);
+ if (FAIL == mysqlnd_real_read(conn, buffer, MYSQLND_HEADER_SIZE TSRMLS_CC)) {
+ DBG_RETURN(FAIL);
+ }
header->size = uint3korr(buffer);
header->packet_no = uint1korr(buffer + 3);
+#ifdef MYSQLND_DUMP_HEADER_N_BODY
+ DBG_INF_FMT("HEADER: prot_packet_no=%d size=%3d", header->packet_no, header->size);
+#endif
MYSQLND_INC_CONN_STATISTIC_W_VALUE3(&conn->stats,
STAT_BYTES_RECEIVED, MYSQLND_HEADER_SIZE,
STAT_PROTOCOL_OVERHEAD_IN, MYSQLND_HEADER_SIZE,
STAT_PACKETS_RECEIVED, 1);
- if (net->packet_no == header->packet_no) {
+ if (net->compressed || net->packet_no == header->packet_no) {
/*
Have to increase the number, so we can send correct number back. It will
round at 255 as this is unsigned char. The server needs this for simple
flow control checking.
*/
net->packet_no++;
-#ifdef MYSQLND_DUMP_HEADER_N_BODY
- DBG_ERR_FMT("HEADER: packet_no=%d size=%3d", header->packet_no, header->size);
-#endif
DBG_RETURN(PASS);
}
- DBG_ERR_FMT("Packets out of order. Expected %d received %d. Packet size=%d",
+ DBG_ERR_FMT("Logical link: packets out of order. Expected %d received %d. Packet size=%d",
net->packet_no, header->packet_no, header->size);
php_error(E_WARNING, "Packets out of order. Expected %d received %d. Packet size="MYSQLND_SZ_T_SPEC,
@@ -507,52 +772,15 @@ mysqlnd_read_header(MYSQLND *conn, mysqlnd_packet_header *header TSRMLS_DC)
/* {{{ mysqlnd_read_body */
-static
-size_t mysqlnd_read_body(MYSQLND *conn, zend_uchar *buf, size_t size TSRMLS_DC)
+static enum_func_status
+mysqlnd_read_body(MYSQLND *conn, mysqlnd_packet_header * header, zend_uchar * store_buf TSRMLS_DC)
{
- size_t ret;
- char *p = (char *)buf;
- unsigned int iter = 0;
MYSQLND_NET *net = &conn->net;
- size_t old_chunk_size = net->stream->chunk_size;
DBG_ENTER(mysqlnd_read_body_name);
- DBG_INF_FMT("chunk_size=%d", net->stream->chunk_size);
-
- net->stream->chunk_size = MIN(size, conn->options.net_read_buffer_size);
- do {
- size -= (ret = php_stream_read(net->stream, p, size));
- if (size > 0 || iter++) {
- DBG_INF_FMT("read=%d buf=%p p=%p chunk_size=%d left=%d",
- ret, buf, p , net->stream->chunk_size, size);
- }
- p += ret;
- } while (size > 0);
-
- MYSQLND_INC_CONN_STATISTIC_W_VALUE(&conn->stats, STAT_BYTES_RECEIVED, p - (char*)buf);
- net->stream->chunk_size = old_chunk_size;
+ DBG_INF_FMT("chunk_size=%d compression=%d", net->stream->chunk_size, net->compressed);
-#ifdef MYSQLND_DUMP_HEADER_N_BODY_FULL
- {
- unsigned int i;
- DBG_INF_FMT("BODY: requested=%d last_read=%3d", p - (char*)buf, ret);
- for (i = 0 ; i < p - (char*)buf; i++) {
- if (i && (i % 30 == 0)) {
- printf("\n\t\t");
- }
- printf("[%c] ", *(char *)(&(buf[i])));
- }
- for (i = 0 ; i < p - (char*)buf; i++) {
- if (i && (i % 30 == 0)) {
- printf("\n\t\t");
- }
- printf("%.2X ", (int)*((char*)&(buf[i])));
- }
- php_printf("\n\t\t\t-=-=-=-=-\n");
- }
-#endif
-
- DBG_RETURN(p - (char*)buf);
+ DBG_RETURN(mysqlnd_real_read(conn, store_buf, header->size TSRMLS_CC));
}
/* }}} */
@@ -561,7 +789,7 @@ size_t mysqlnd_read_body(MYSQLND *conn, zend_uchar *buf, size_t size TSRMLS_DC)
static enum_func_status
php_mysqlnd_greet_read(void *_packet, MYSQLND *conn TSRMLS_DC)
{
- zend_uchar buf[512];
+ zend_uchar buf[2048];
zend_uchar *p = buf;
zend_uchar *begin = buf;
php_mysql_packet_greet *packet= (php_mysql_packet_greet *) _packet;
@@ -678,7 +906,7 @@ void php_mysqlnd_scramble(zend_uchar * const buffer, const zend_uchar * const sc
PHP_SHA1_CTX context;
zend_uchar sha1[SHA1_MAX_LENGTH];
zend_uchar sha2[SHA1_MAX_LENGTH];
-
+
/* Phase 1: hash password */
PHP_SHA1Init(&context);
@@ -722,7 +950,7 @@ size_t php_mysqlnd_auth_write(void *_packet, MYSQLND *conn TSRMLS_DC)
if (PG(open_basedir) && strlen(PG(open_basedir))) {
packet->client_flags ^= CLIENT_LOCAL_FILES;
}
-
+
int4store(p, packet->client_flags);
p+= 4;
@@ -733,7 +961,7 @@ size_t php_mysqlnd_auth_write(void *_packet, MYSQLND *conn TSRMLS_DC)
p++;
memset(p, 0, 23); /* filler */
- p+= 23;
+ p+= 23;
len= strlen(packet->user);
memcpy(p, packet->user, len);
@@ -765,6 +993,7 @@ size_t php_mysqlnd_auth_write(void *_packet, MYSQLND *conn TSRMLS_DC)
}
/* }}} */
+
/* {{{ php_mysqlnd_auth_free_mem */
static
void php_mysqlnd_auth_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
@@ -776,11 +1005,15 @@ void php_mysqlnd_auth_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
/* }}} */
+#define OK_BUFFER_SIZE 2048
+
/* {{{ php_mysqlnd_ok_read */
static enum_func_status
php_mysqlnd_ok_read(void *_packet, MYSQLND *conn TSRMLS_DC)
{
- zend_uchar buf[1024];
+ zend_uchar local_buf[OK_BUFFER_SIZE];
+ size_t buf_len = conn->net.cmd_buffer.buffer? conn->net.cmd_buffer.length : OK_BUFFER_SIZE;
+ zend_uchar *buf = conn->net.cmd_buffer.buffer? (zend_uchar *) conn->net.cmd_buffer.buffer : local_buf;
zend_uchar *p = buf;
zend_uchar *begin = buf;
unsigned long i;
@@ -788,7 +1021,7 @@ php_mysqlnd_ok_read(void *_packet, MYSQLND *conn TSRMLS_DC)
DBG_ENTER("php_mysqlnd_ok_read");
- PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "OK", PROT_OK_PACKET);
+ PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "OK", PROT_OK_PACKET);
/* Should be always 0x0 or 0xFF for error */
packet->field_count = uint1korr(p);
@@ -813,7 +1046,7 @@ php_mysqlnd_ok_read(void *_packet, MYSQLND *conn TSRMLS_DC)
/* There is a message */
if (packet->header.size > p - buf && (i = php_mysqlnd_net_field_length(&p))) {
- packet->message = estrndup((char *)p, MIN(i, sizeof(buf) - (p - buf)));
+ packet->message = estrndup((char *)p, MIN(i, buf_len - (p - begin)));
packet->message_len = i;
} else {
packet->message = NULL;
@@ -861,13 +1094,14 @@ php_mysqlnd_eof_read(void *_packet, MYSQLND *conn TSRMLS_DC)
Error : error_code + '#' + sqlstate + MYSQLND_ERRMSG_SIZE
*/
php_mysql_packet_eof *packet= (php_mysql_packet_eof *) _packet;
- zend_uchar buf[5 + 10 + sizeof(packet->sqlstate) + sizeof(packet->error)];
+ size_t buf_len = conn->net.cmd_buffer.length;
+ zend_uchar *buf = (zend_uchar *) conn->net.cmd_buffer.buffer;
zend_uchar *p = buf;
zend_uchar *begin = buf;
DBG_ENTER("php_mysqlnd_eof_read");
- PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "EOF", PROT_EOF_PACKET);
+ PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "EOF", PROT_EOF_PACKET);
/* Should be always 0xFE */
packet->field_count = uint1korr(p);
@@ -901,7 +1135,7 @@ php_mysqlnd_eof_read(void *_packet, MYSQLND *conn TSRMLS_DC)
php_error_docref(NULL TSRMLS_CC, E_WARNING, "EOF packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
p - begin - packet->header.size);
}
-
+
DBG_INF_FMT("EOF packet: fields=%d status=%d warnings=%d",
packet->field_count, packet->server_status, packet->warning_count);
@@ -936,13 +1170,14 @@ size_t php_mysqlnd_cmd_write(void *_packet, MYSQLND *conn TSRMLS_DC)
Every command starts a new TX and packet numbers are reset to 0.
*/
net->packet_no = 0;
+ net->compressed_envelope_packet_no = 0; /* this is for the response */
if (error_reporting) {
EG(error_reporting) = 0;
}
MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_PACKETS_SENT_CMD);
-
+
#ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
php_mysqlnd_consume_uneaten_data(conn, packet->command TSRMLS_CC);
#endif
@@ -953,10 +1188,6 @@ size_t php_mysqlnd_cmd_write(void *_packet, MYSQLND *conn TSRMLS_DC)
int1store(buffer + MYSQLND_HEADER_SIZE, packet->command);
written = mysqlnd_stream_write_w_header(conn, buffer, 1 TSRMLS_CC);
} else {
-#if USE_CORK && defined(TCP_CORK)
- written = mysqlnd_stream_write_w_command(conn, packet->command, packet->argument,
- packet->arg_len TSRMLS_CC));
-#else
size_t tmp_len = packet->arg_len + 1 + MYSQLND_HEADER_SIZE, ret;
zend_uchar *tmp, *p;
tmp = (tmp_len > net->cmd_buffer.length)? mnd_emalloc(tmp_len):net->cmd_buffer.buffer;
@@ -973,7 +1204,6 @@ size_t php_mysqlnd_cmd_write(void *_packet, MYSQLND *conn TSRMLS_DC)
mnd_efree(tmp);
}
written = ret;
-#endif
}
if (error_reporting) {
/* restore error reporting */
@@ -999,7 +1229,8 @@ void php_mysqlnd_cmd_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
static enum_func_status
php_mysqlnd_rset_header_read(void *_packet, MYSQLND *conn TSRMLS_DC)
{
- zend_uchar buf[1024];
+ size_t buf_len = conn->net.cmd_buffer.length;
+ zend_uchar *buf = (zend_uchar *) conn->net.cmd_buffer.buffer;
zend_uchar *p = buf;
zend_uchar *begin = buf;
size_t len;
@@ -1007,7 +1238,7 @@ php_mysqlnd_rset_header_read(void *_packet, MYSQLND *conn TSRMLS_DC)
DBG_ENTER("php_mysqlnd_rset_header_read");
- PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "resultset header", PROT_RSET_HEADER_PACKET);
+ PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "resultset header", PROT_RSET_HEADER_PACKET);
/*
Don't increment. First byte is 0xFF on error, but otherwise is starting byte
@@ -1076,6 +1307,7 @@ php_mysqlnd_rset_header_read(void *_packet, MYSQLND *conn TSRMLS_DC)
static
void php_mysqlnd_rset_header_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
{
+ DBG_ENTER("php_mysqlnd_rset_header_free_mem");
php_mysql_packet_rset_header *p= (php_mysql_packet_rset_header *) _packet;
if (p->info_or_local_file) {
mnd_efree(p->info_or_local_file);
@@ -1084,6 +1316,7 @@ void php_mysqlnd_rset_header_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
if (!alloca) {
mnd_pefree(p, p->header.persistent);
}
+ DBG_VOID_RETURN;
}
/* }}} */
@@ -1110,11 +1343,11 @@ php_mysqlnd_rset_field_read(void *_packet, MYSQLND *conn TSRMLS_DC)
{
/* Should be enough for the metadata of a single row */
php_mysql_packet_res_field *packet= (php_mysql_packet_res_field *) _packet;
+ size_t buf_len = conn->net.cmd_buffer.length, total_len = 0;
zend_uchar *buf = (zend_uchar *) conn->net.cmd_buffer.buffer;
zend_uchar *p = buf;
zend_uchar *begin = buf;
char *root_ptr;
- size_t buf_len = conn->net.cmd_buffer.length, total_len = 0;
unsigned long len;
MYSQLND_FIELD *meta;
unsigned int i, field_count = sizeof(rset_field_offsets)/sizeof(size_t);
@@ -1289,7 +1522,8 @@ void php_mysqlnd_rset_field_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
static enum_func_status
-php_mysqlnd_read_row_ex(MYSQLND *conn, MYSQLND_MEMORY_POOL_CHUNK **buffer,
+php_mysqlnd_read_row_ex(MYSQLND *conn, MYSQLND_MEMORY_POOL * result_set_memory_pool,
+ MYSQLND_MEMORY_POOL_CHUNK **buffer,
uint64_t *data_size, zend_bool persistent_alloc,
unsigned int prealloc_more_bytes TSRMLS_DC)
{
@@ -1323,8 +1557,7 @@ php_mysqlnd_read_row_ex(MYSQLND *conn, MYSQLND_MEMORY_POOL_CHUNK **buffer,
We need a trailing \0 for the last string, in case of text-mode,
to be able to implement read-only variables. Thus, we add + 1.
*/
- *buffer = conn->result_set_memory_pool->get_chunk(conn->result_set_memory_pool,
- *data_size + 1 TSRMLS_CC);
+ *buffer = result_set_memory_pool->get_chunk(result_set_memory_pool, *data_size + 1 TSRMLS_CC);
p = (*buffer)->ptr;
} else if (!first_iteration) {
/* Empty packet after MYSQLND_MAX_PACKET_SIZE packet. That's ok, break */
@@ -1343,10 +1576,9 @@ php_mysqlnd_read_row_ex(MYSQLND *conn, MYSQLND_MEMORY_POOL_CHUNK **buffer,
p = (*buffer)->ptr + (*data_size - header.size);
}
- if (!mysqlnd_read_body(conn, p, header.size TSRMLS_CC)) {
+ if ((ret = mysqlnd_read_body(conn, &header, p TSRMLS_CC))) {
DBG_ERR("Empty row packet body");
php_error(E_WARNING, "Empty row packet body");
- ret = FAIL;
break;
}
@@ -1354,7 +1586,7 @@ php_mysqlnd_read_row_ex(MYSQLND *conn, MYSQLND_MEMORY_POOL_CHUNK **buffer,
break;
}
}
- if (ret == FAIL) {
+ if (ret == FAIL && *buffer) {
(*buffer)->free_chunk((*buffer), TRUE TSRMLS_CC);
*buffer = NULL;
}
@@ -1365,14 +1597,16 @@ php_mysqlnd_read_row_ex(MYSQLND *conn, MYSQLND_MEMORY_POOL_CHUNK **buffer,
/* {{{ php_mysqlnd_rowp_read_binary_protocol */
void php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
- unsigned int field_count, MYSQLND_FIELD *fields_metadata,
- MYSQLND *conn TSRMLS_DC)
+ unsigned int field_count, MYSQLND_FIELD *fields_metadata,
+ zend_bool persistent,
+ zend_bool as_unicode, zend_bool as_int_or_float,
+ MYSQLND_THD_ZVAL_PCACHE * zval_cache,
+ MYSQLND_STATS * stats TSRMLS_DC)
{
int i;
zend_uchar *p = row_buffer->ptr;
zend_uchar *null_ptr, bit;
zval **current_field, **end_field, **start_field;
- zend_bool as_unicode = conn->options.numeric_and_datetime_as_unicode;
#ifdef USE_ZVAL_CACHE
zend_bool allocated;
void *obj;
@@ -1392,12 +1626,12 @@ void php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffe
for (i = 0; current_field < end_field; current_field++, i++) {
#ifdef USE_ZVAL_CACHE
DBG_INF("Trying to use the zval cache");
- obj = mysqlnd_palloc_get_zval(conn->zval_cache, &allocated TSRMLS_CC);
+ obj = mysqlnd_palloc_get_zval(zval_cache, &allocated TSRMLS_CC);
if (allocated) {
*current_field = (zval *) obj;
} else {
/* It's from the cache, so we can upcast here */
- *current_field = &((mysqlnd_zval *) obj)->zv;
+ *current_field = &((mysqlnd_zval *) obj)->zv;
((mysqlnd_zval *) obj)->point_type = MYSQLND_POINTS_EXT_BUFFER;
}
#else
@@ -1412,7 +1646,7 @@ void php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffe
if (*null_ptr & bit) {
DBG_INF("It's null");
ZVAL_NULL(*current_field);
- MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_BINARY_TYPE_FETCHED_NULL);
+ MYSQLND_INC_CONN_STATISTIC(stats, STAT_BINARY_TYPE_FETCHED_NULL);
} else {
enum_mysqlnd_field_types type = fields_metadata[i].type;
mysqlnd_ps_fetch_functions[type].func(*current_field, &fields_metadata[i],
@@ -1449,8 +1683,8 @@ void php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffe
case MYSQL_TYPE_STRING: statistic = STAT_BINARY_TYPE_FETCHED_STRING; break;
case MYSQL_TYPE_GEOMETRY: statistic = STAT_BINARY_TYPE_FETCHED_GEOMETRY; break;
default: statistic = STAT_BINARY_TYPE_FETCHED_OTHER; break;
- }
- MYSQLND_INC_CONN_STATISTIC(&conn->stats, statistic);
+ }
+ MYSQLND_INC_CONN_STATISTIC(stats, statistic);
}
}
if (!((bit<<=1) & 255)) {
@@ -1467,7 +1701,10 @@ void php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffe
/* {{{ php_mysqlnd_rowp_read_text_protocol */
void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
unsigned int field_count, MYSQLND_FIELD *fields_metadata,
- MYSQLND *conn TSRMLS_DC)
+ zend_bool persistent,
+ zend_bool as_unicode, zend_bool as_int_or_float,
+ MYSQLND_THD_ZVAL_PCACHE * zval_cache,
+ MYSQLND_STATS * stats TSRMLS_DC)
{
int i;
zend_bool last_field_was_string = FALSE;
@@ -1475,10 +1712,6 @@ void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
zend_uchar *p = row_buffer->ptr;
size_t data_size = row_buffer->app;
zend_uchar *bit_area = (zend_uchar*) row_buffer->ptr + data_size + 1; /* we allocate from here */
- zend_bool as_unicode = conn->options.numeric_and_datetime_as_unicode;
-#ifdef MYSQLND_STRING_TO_INT_CONVERSION
- zend_bool as_int_or_float = conn->options.int_and_float_native;
-#endif
DBG_ENTER("php_mysqlnd_rowp_read_text_protocol");
@@ -1492,12 +1725,12 @@ void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
unsigned long len = php_mysqlnd_net_field_length(&p);
#ifdef USE_ZVAL_CACHE
- obj = mysqlnd_palloc_get_zval(conn->zval_cache, &allocated TSRMLS_CC);
+ obj = mysqlnd_palloc_get_zval(zval_cache, &allocated TSRMLS_CC);
if (allocated) {
*current_field = (zval *) obj;
} else {
/* It's from the cache, so we can upcast here */
- *current_field = &((mysqlnd_zval *) obj)->zv;
+ *current_field = &((mysqlnd_zval *) obj)->zv;
((mysqlnd_zval *) obj)->point_type = MYSQLND_POINTS_FREE;
}
#else
@@ -1507,7 +1740,7 @@ void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
if (current_field > start_field && last_field_was_string) {
/*
- Normal queries:
+ Normal queries:
We have to put \0 now to the end of the previous field, if it was
a string. IS_NULL doesn't matter. Because we have already read our
length, then we can overwrite it in the row buffer.
@@ -1561,8 +1794,8 @@ void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
case MYSQL_TYPE_STRING: statistic = STAT_TEXT_TYPE_FETCHED_STRING; break;
case MYSQL_TYPE_GEOMETRY: statistic = STAT_TEXT_TYPE_FETCHED_GEOMETRY; break;
default: statistic = STAT_TEXT_TYPE_FETCHED_OTHER; break;
- }
- MYSQLND_INC_CONN_STATISTIC(&conn->stats, statistic);
+ }
+ MYSQLND_INC_CONN_STATISTIC(stats, statistic);
}
#ifdef MYSQLND_STRING_TO_INT_CONVERSION
@@ -1594,7 +1827,7 @@ void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
#if SIZEOF_LONG==8
if (uns == TRUE && v > 9223372036854775807L)
#elif SIZEOF_LONG==4
- if ((uns == TRUE && v > L64(2147483647)) ||
+ if ((uns == TRUE && v > L64(2147483647)) ||
(uns == FALSE && (( L64(2147483647) < (int64_t) v) ||
(L64(-2147483648) > (int64_t) v))))
#endif /* SIZEOF */
@@ -1636,7 +1869,7 @@ void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
#if PHP_MAJOR_VERSION >= 6
if (as_unicode) {
ZVAL_UTF8_STRINGL(*current_field, start, bit_area - start - 1, 0);
- } else
+ } else
#endif
{
ZVAL_STRINGL(*current_field, (char *) start, bit_area - start - 1, 0);
@@ -1652,7 +1885,7 @@ void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
#if PHP_MAJOR_VERSION >= 6
if (as_unicode) {
ZVAL_UTF8_STRINGL(*current_field, start, bit_area - start - 1, 0);
- } else
+ } else
#endif
{
ZVAL_STRINGL(*current_field, (char *) start, bit_area - start - 1, 0);
@@ -1665,7 +1898,7 @@ void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
IS_UNICODE should not be specially handled. In unicode mode
the buffers are not referenced - everything is copied.
*/
- } else
+ } else
#if PHP_MAJOR_VERSION < 6
{
ZVAL_STRINGL(*current_field, (char *)p, len, 0);
@@ -1730,7 +1963,7 @@ void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
/* {{{ php_mysqlnd_rowp_read */
/*
- if normal statements => packet->fields is created by this function,
+ if normal statements => packet->fields is created by this function,
if PS => packet->fields is passed from outside
*/
static enum_func_status
@@ -1752,7 +1985,7 @@ php_mysqlnd_rowp_read(void *_packet, MYSQLND *conn TSRMLS_DC)
packet->bit_fields_total_len + packet->bit_fields_count;
}
- ret = php_mysqlnd_read_row_ex(conn, &packet->row_buffer, &data_size,
+ ret = php_mysqlnd_read_row_ex(conn, packet->result_set_memory_pool, &packet->row_buffer, &data_size,
packet->persistent_alloc, post_alloc_for_bit_fields
TSRMLS_CC);
if (FAIL == ret) {
@@ -1862,12 +2095,13 @@ void php_mysqlnd_rowp_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
static enum_func_status
php_mysqlnd_stats_read(void *_packet, MYSQLND *conn TSRMLS_DC)
{
- zend_uchar buf[1024];
php_mysql_packet_stats *packet= (php_mysql_packet_stats *) _packet;
+ size_t buf_len = conn->net.cmd_buffer.length;
+ zend_uchar *buf = (zend_uchar *) conn->net.cmd_buffer.buffer;
DBG_ENTER("php_mysqlnd_stats_read");
- PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "statistics", PROT_STATS_PACKET);
+ PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "statistics", PROT_STATS_PACKET);
packet->message = mnd_emalloc(packet->header.size + 1);
memcpy(packet->message, buf, packet->header.size);
@@ -1904,7 +2138,8 @@ static enum_func_status
php_mysqlnd_prepare_read(void *_packet, MYSQLND *conn TSRMLS_DC)
{
/* In case of an error, we should have place to put it */
- zend_uchar buf[1024];
+ size_t buf_len = conn->net.cmd_buffer.length;
+ zend_uchar *buf = (zend_uchar *) conn->net.cmd_buffer.buffer;
zend_uchar *p = buf;
zend_uchar *begin = buf;
unsigned int data_size;
@@ -1912,8 +2147,8 @@ php_mysqlnd_prepare_read(void *_packet, MYSQLND *conn TSRMLS_DC)
DBG_ENTER("php_mysqlnd_prepare_read");
- PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "prepare", PROT_PREPARE_RESP_PACKET);
-
+ PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "prepare", PROT_PREPARE_RESP_PACKET);
+
data_size = packet->header.size;
packet->error_code = uint1korr(p);
p++;
@@ -1984,14 +2219,15 @@ static enum_func_status
php_mysqlnd_chg_user_read(void *_packet, MYSQLND *conn TSRMLS_DC)
{
/* There could be an error message */
- zend_uchar buf[1024];
+ size_t buf_len = conn->net.cmd_buffer.length;
+ zend_uchar *buf = (zend_uchar *) conn->net.cmd_buffer.buffer;
zend_uchar *p = buf;
zend_uchar *begin = buf;
php_mysql_packet_chg_user_resp *packet= (php_mysql_packet_chg_user_resp *) _packet;
DBG_ENTER("php_mysqlnd_chg_user_read");
- PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "change user response", PROT_CHG_USER_PACKET);
+ PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "change user response", PROT_CHG_USER_PACKET);
/*
Don't increment. First byte is 0xFF on error, but otherwise is starting byte
@@ -2038,7 +2274,7 @@ void php_mysqlnd_chg_user_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
/* }}} */
-/* {{{ packet_methods
+/* {{{ packet_methods
*/
mysqlnd_packet_methods packet_methods[PROT_LAST] =
{
diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.h b/ext/mysqlnd/mysqlnd_wireprotocol.h
index 77ee795c35..ae05cb68db 100644
--- a/ext/mysqlnd/mysqlnd_wireprotocol.h
+++ b/ext/mysqlnd/mysqlnd_wireprotocol.h
@@ -24,6 +24,7 @@
#define MYSQLND_WIREPROTOCOL_H
#define MYSQLND_HEADER_SIZE 4
+#define COMPRESSED_HEADER_SIZE 3
#define MYSQLND_NULL_LENGTH (unsigned long) ~0
@@ -261,6 +262,7 @@ struct st_php_mysql_packet_row {
uint16_t server_status;
struct st_mysqlnd_memory_pool_chunk *row_buffer;
+ MYSQLND_MEMORY_POOL * result_set_memory_pool;
zend_bool skip_extraction;
zend_bool binary_protocol;
@@ -303,7 +305,7 @@ typedef struct st_php_mysql_packet_prepare_response {
typedef struct st_php_mysql_packet_chg_user_resp {
mysqlnd_packet_header header;
uint32_t field_count;
-
+
/* message_len is not part of the packet*/
uint16_t server_capabilities;
/* If error packet, we use these */
@@ -311,8 +313,8 @@ typedef struct st_php_mysql_packet_chg_user_resp {
} php_mysql_packet_chg_user_resp;
-size_t mysqlnd_stream_write(MYSQLND * const conn, char * const buf, size_t count TSRMLS_DC);
size_t mysqlnd_stream_write_w_header(MYSQLND * const conn, char * const buf, size_t count TSRMLS_DC);
+size_t mysqlnd_stream_write(MYSQLND * const conn, const zend_uchar * const buf, size_t count TSRMLS_DC);
#ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
size_t php_mysqlnd_consume_uneaten_data(MYSQLND * const conn, enum php_mysqlnd_server_command cmd TSRMLS_DC);
@@ -327,10 +329,22 @@ extern char * const mysqlnd_empty_string;
void php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
- unsigned int field_count, MYSQLND_FIELD *fields_metadata, MYSQLND *conn TSRMLS_DC);
+ unsigned int field_count, MYSQLND_FIELD *fields_metadata,
+ zend_bool persistent,
+ zend_bool as_unicode, zend_bool as_int_or_float,
+ MYSQLND_THD_ZVAL_PCACHE * zval_cache,
+ MYSQLND_STATS * stats TSRMLS_DC);
+
void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
- unsigned int field_count, MYSQLND_FIELD *fields_metadata, MYSQLND *conn TSRMLS_DC);
+ unsigned int field_count, MYSQLND_FIELD *fields_metadata,
+ zend_bool persistent,
+ zend_bool as_unicode, zend_bool as_int_or_float,
+ MYSQLND_THD_ZVAL_PCACHE * zval_cache,
+ MYSQLND_STATS * stats TSRMLS_DC);
+
+enum_func_status mysqlnd_read_from_stream(MYSQLND * conn, zend_uchar * buffer, size_t count TSRMLS_DC);
+
#endif /* MYSQLND_WIREPROTOCOL_H */
diff --git a/ext/mysqlnd/php_mysqlnd.c b/ext/mysqlnd/php_mysqlnd.c
index 1465681bd3..585e5d86a7 100644
--- a/ext/mysqlnd/php_mysqlnd.c
+++ b/ext/mysqlnd/php_mysqlnd.c
@@ -102,6 +102,12 @@ PHP_MINFO_FUNCTION(mysqlnd)
php_info_print_table_start();
php_info_print_table_header(2, "mysqlnd", "enabled");
php_info_print_table_row(2, "Version", mysqlnd_get_client_info());
+ php_info_print_table_row(2, "Compression",
+#ifdef MYSQLND_COMPRESSION_ENABLED
+ "supported");
+#else
+ "not supported");
+#endif
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));
@@ -234,10 +240,18 @@ static PHP_RSHUTDOWN_FUNCTION(mysqlnd)
#endif
+
+static const zend_module_dep mysqlnd_deps[] = {
+ ZEND_MOD_REQUIRED("standard")
+ {NULL, NULL, NULL}
+};
+
/* {{{ mysqlnd_module_entry
*/
zend_module_entry mysqlnd_module_entry = {
- STANDARD_MODULE_HEADER,
+ STANDARD_MODULE_HEADER_EX,
+ NULL,
+ mysqlnd_deps,
"mysqlnd",
mysqlnd_functions,
PHP_MINIT(mysqlnd),