Compressed protocol support + extensibility for mysqlnd

This commit is contained in:
Andrey Hristov 2009-11-20 08:12:14 +00:00
parent 4e010297f1
commit 5143fe41e2
15 changed files with 842 additions and 355 deletions

View file

@ -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");
}
}
}
}

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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

View file

@ -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 */

View file

@ -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

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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;
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;
#ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
zend_uchar last_command;
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;
#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;
};

File diff suppressed because it is too large Load diff

View file

@ -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 */

View file

@ -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),