"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
+}
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 \
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
#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 */
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;
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) {
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);
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
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;
/* {{{ _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);
/* }}} */
-/* {{{ 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,
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);
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]) {
}
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;
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);
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());
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);
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) {
}
} 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);
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;
PACKET_FREE(auth_packet);
PACKET_FREE_ALLOCA(ok_packet);
- DBG_RETURN(conn);
+ DBG_RETURN(PASS);
}
err:
PACKET_FREE_ALLOCA(greet_packet);
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
*/
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);
}
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));
}
/* }}} */
}
p++;
}
- *ret_p = NULL;
+ *ret_p = NULL;
}
return ret;
}
* */
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) {
fwd++;
}
*bckwd = NULL;/* NULL-terminate the list */
-
+
return ret;
}
/* 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) {
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';
}
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)) {
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));
}
/* }}} */
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
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),
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),
/* {{{ 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);
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();
}
/* }}} */
+
+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
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)
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);
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;
}
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;
}
{ 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},
{ 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},
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 */
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;
#endif
+#define MYSQLND_MIN_COMPRESS_LEN 0
+
#define MYSQLND_MAX_PACKET_SIZE (256L*256L*256L-1)
#define MYSQLND_ERRMSG_SIZE 512
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);
}
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 */
#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
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 */
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 */
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++) {
/*
/*
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;
*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;
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);
} 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.
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;
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++) {
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);
} 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.
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,
#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"
#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;
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
/* }}} */
-/* {{{ 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;
/* }}} */
-/* {{{ 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));
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
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;
}
/* }}} */
/*
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;
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 *));
} 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);
/*
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;
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];
} 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;
}
}
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
*/
/* 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;
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
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
#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);
/* 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;
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;
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++) {
/*
/* 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;
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++) {
/*
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));
}
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));
}
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));
}
/* {{{ 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);
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;
}
/* }}} */
+
+/* {{{ _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
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
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;
} 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);
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);
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);
};
/* Temporal storage for mysql_query */
unsigned int field_count;
-
+
/* persistent connection */
zend_bool persistent;
/* qcache */
MYSQLND_QCACHE *qcache;
- MYSQLND_MEMORY_POOL * result_set_memory_pool;
-
/* stats */
MYSQLND_STATS stats;
#if PHP_MAJOR_VERSION >= 6
zstr ustr;
unsigned int ulen;
-#endif
+#endif
};
/*
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;
/* zval cache */
MYSQLND_THD_ZVAL_PCACHE *zval_cache;
+
+ MYSQLND_MEMORY_POOL * result_set_memory_pool;
};
+
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
#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>
#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);\
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], \
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] =
{
};
-/* {{{ 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)
{
/* }}} */
-/* {{{ 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)
{
/* }}} */
+#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)
/* {{{ 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;
}
sqlstate[MYSQLND_SQLSTATE_LENGTH] = '\0';
error[error_msg_len]= '\0';
-
+
DBG_RETURN(FAIL);
-}
+}
/* }}} */
/* }}} */
+/* {{{ 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))
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);
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,
/* {{{ 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));
}
/* }}} */
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;
PHP_SHA1_CTX context;
zend_uchar sha1[SHA1_MAX_LENGTH];
zend_uchar sha2[SHA1_MAX_LENGTH];
-
+
/* Phase 1: hash password */
PHP_SHA1Init(&context);
if (PG(open_basedir) && strlen(PG(open_basedir))) {
packet->client_flags ^= CLIENT_LOCAL_FILES;
}
-
+
int4store(p, packet->client_flags);
p+= 4;
p++;
memset(p, 0, 23); /* filler */
- p+= 23;
+ p+= 23;
len= strlen(packet->user);
memcpy(p, packet->user, len);
}
/* }}} */
+
/* {{{ php_mysqlnd_auth_free_mem */
static
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;
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);
/* 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;
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);
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);
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
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;
mnd_efree(tmp);
}
written = ret;
-#endif
}
if (error_reporting) {
/* restore error reporting */
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;
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
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);
if (!alloca) {
mnd_pefree(p, p->header.persistent);
}
+ DBG_VOID_RETURN;
}
/* }}} */
{
/* 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);
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)
{
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 */
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;
}
break;
}
}
- if (ret == FAIL) {
+ if (ret == FAIL && *buffer) {
(*buffer)->free_chunk((*buffer), TRUE TSRMLS_CC);
*buffer = NULL;
}
/* {{{ 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;
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
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],
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)) {
/* {{{ 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;
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");
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
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.
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
#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 */
#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);
#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);
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);
/* {{{ 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
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) {
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);
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;
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++;
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
/* }}} */
-/* {{{ packet_methods
+/* {{{ packet_methods
*/
mysqlnd_packet_methods packet_methods[PROT_LAST] =
{
#define MYSQLND_WIREPROTOCOL_H
#define MYSQLND_HEADER_SIZE 4
+#define COMPRESSED_HEADER_SIZE 3
#define MYSQLND_NULL_LENGTH (unsigned long) ~0
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;
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 */
} 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);
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 */
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));
#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),