]> granicus.if.org Git - php/commitdiff
Compressed protocol support + extensibility for mysqlnd
authorAndrey Hristov <andrey@php.net>
Fri, 20 Nov 2009 08:12:14 +0000 (08:12 +0000)
committerAndrey Hristov <andrey@php.net>
Fri, 20 Nov 2009 08:12:14 +0000 (08:12 +0000)
15 files changed:
ext/mysqlnd/config.w32
ext/mysqlnd/config9.m4
ext/mysqlnd/mysqlnd.c
ext/mysqlnd/mysqlnd.h
ext/mysqlnd/mysqlnd_charset.c
ext/mysqlnd/mysqlnd_enum_n_def.h
ext/mysqlnd/mysqlnd_loaddata.c
ext/mysqlnd/mysqlnd_priv.h
ext/mysqlnd/mysqlnd_ps.c
ext/mysqlnd/mysqlnd_result.c
ext/mysqlnd/mysqlnd_result.h
ext/mysqlnd/mysqlnd_structs.h
ext/mysqlnd/mysqlnd_wireprotocol.c
ext/mysqlnd/mysqlnd_wireprotocol.h
ext/mysqlnd/php_mysqlnd.c

index d495672cf710f2316f7d84f9e7f43f6d55c998bf..00a3f147c0609a61fa913df2529cd53c0e267525 100644 (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");
+               }
        }
-}
\ No newline at end of file
+}
index 59fd6c74cc8df65d07ff23abe1b94c43cc365dd9..b3b802cd3894e6e6f18956932e79b233f224de01 100644 (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
index 3e48550bf899f9ec05ebeb0714ad3cbce42c1f2f..d0de0738374eacbc2e0ed489dedd5456ee188083 100644 (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
index 9dfea4bbefa882effcb25458d9d0dd122bb2cf1a..274c617f79332c40debdc5d5252d11d57a8f46f4 100644 (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)
 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);
 
index 3fc434cc5a6ccc80552aa6dfb272e1c44e86bfbf..e36cb64df97092f1143a9a1ad47bcf9ad9eb4031 100644 (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;
index 9bef37b9ea26aae50bcea7f40ef79397ca4ba91c..1735de5e775565673fd425dad67ca9571dbe9b73 100644 (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
index f37aff51b3924deae07ae217e72bddabb27bc0d3..c050f4019f259247a2382a435559eae8ae02f075 100644 (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 */
index 759c91e085f2e753c8ef874eda0a23b082443504..fc99d4e07639d61e4f23ceceb5fdb951e636dcf7 100644 (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
index c788fdcd4df1106fb06b6f902bff270e7068b6f3..9fc1d5d6601b94d61bd365966613fe6aefa5e68e 100644 (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,
index 785421e6b262e1ca640bab666754bddf50cc764c..82b396c6747bd7619defc955cac6bbcc981fe933 100644 (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
index 981c300dee679148ca24bbbb61b5cf8c1e951529..8308204a6ba2da12b68fe8067c7d23b33def9aca 100644 (file)
 
 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
index b54ea7fa7a147962aa5b30ddd4be7c5dc56f3621..0763e0148d2b2af0b3caaed7207129626024be32 100644 (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;
-       /* sequence for simple checking of correct packets */
-       zend_uchar              packet_no;
+       php_stream                      *stream;
+       enum_func_status        (*stream_read)(MYSQLND * conn, zend_uchar * buffer, size_t count TSRMLS_DC);
+       size_t                          (*stream_write)(MYSQLND * const conn, const zend_uchar * const buf, size_t count TSRMLS_DC);
 
+       /* sequence for simple checking of correct packets */
+       zend_uchar                      packet_no;
+       zend_bool                       compressed;
+       zend_uchar                      compressed_envelope_packet_no;
+#ifdef MYSQLND_COMPRESSION_ENABLED
+       MYSQLND_READ_BUFFER     * uncompressed_data;
+#endif
 #ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
-       zend_uchar              last_command;
+       zend_uchar                      last_command;
 #endif
-
        /* cmd buffer */
        MYSQLND_CMD_BUFFER      cmd_buffer;
 } MYSQLND_NET;
 
 
+
+
 struct st_mysqlnd_conn_methods
 {
+       enum_func_status        (*connect)(MYSQLND *conn, const char *host, const char * user, const char * passwd, unsigned int passwd_len, const char * db, unsigned int db_len, unsigned int port, const char * socket, unsigned int mysql_flags, MYSQLND_THD_ZVAL_PCACHE * zval_cache TSRMLS_DC);
        ulong                           (*escape_string)(const MYSQLND * const conn, char *newstr, const char *escapestr, size_t escapestr_len TSRMLS_DC);
        enum_func_status        (*set_charset)(MYSQLND * const conn, const char * const charset TSRMLS_DC);
        enum_func_status        (*query)(MYSQLND *conn, const char *query, unsigned int query_len TSRMLS_DC);
@@ -285,6 +306,8 @@ struct st_mysqlnd_conn_methods
        enum_func_status        (*close)(MYSQLND *conn, enum_connection_close_type close_type TSRMLS_DC);
        void                            (*dtor)(MYSQLND *conn TSRMLS_DC);       /* private */
 
+       enum_func_status        (*query_read_result_set_header)(MYSQLND *conn, MYSQLND_STMT *stmt TSRMLS_DC);
+
        MYSQLND *                       (*get_reference)(MYSQLND * const conn TSRMLS_DC);
        enum_func_status        (*free_reference)(MYSQLND * const conn TSRMLS_DC);
        enum mysqlnd_connection_state (*get_state)(MYSQLND * const conn TSRMLS_DC);
@@ -317,13 +340,25 @@ struct st_mysqlnd_res_methods
 
        enum_func_status        (*read_result_metadata)(MYSQLND_RES *result, MYSQLND *conn TSRMLS_DC);
        unsigned long *         (*fetch_lengths)(MYSQLND_RES * const result);
+       enum_func_status        (*store_result_fetch_data)(MYSQLND * const conn, MYSQLND_RES *result, MYSQLND_RES_METADATA *meta, zend_bool binary_protocol, zend_bool to_cache TSRMLS_DC);
+       void                            (*initialize_result_set_rest)(MYSQLND_RES * const result TSRMLS_DC);
+
        void                            (*free_result_buffers)(MYSQLND_RES * result TSRMLS_DC); /* private */
        enum_func_status        (*free_result)(MYSQLND_RES * result, zend_bool implicit TSRMLS_DC);
-       void                            (*free_result_internal)(MYSQLND_RES *result TSRMLS_DC);
-       void                            (*free_result_contents)(MYSQLND_RES *result TSRMLS_DC);
+       void                            (*free_result_internal)(MYSQLND_RES *result TSRMLS_DC);
+       void                            (*free_result_contents)(MYSQLND_RES *result TSRMLS_DC);
+       void                            (*free_buffered_data)(MYSQLND_RES *result TSRMLS_DC);
+       void                            (*unbuffered_free_last_data)(MYSQLND_RES *result TSRMLS_DC);
+
+       /* for decoding - binary or text protocol */
+       void                            (*row_decoder)(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
+                                                                       unsigned int field_count, MYSQLND_FIELD *fields_metadata,
+                                                                       zend_bool persistent,
+                                                                       zend_bool as_unicode, zend_bool as_int_or_float,
+                                                                       MYSQLND_THD_ZVAL_PCACHE * zval_cache,
+                                                                       MYSQLND_STATS * stats TSRMLS_DC);
+
 
-       /* for decoding - binary or text protocol */    
-       void                            (*row_decoder)(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields, unsigned int field_count, MYSQLND_FIELD *fields_metadata, MYSQLND *conn TSRMLS_DC);
 };
 
 
@@ -445,7 +480,7 @@ struct st_mysqlnd_connection
 
        /* Temporal storage for mysql_query */
        unsigned int    field_count;
-       
+
        /* persistent connection */
        zend_bool               persistent;
 
@@ -458,8 +493,6 @@ struct st_mysqlnd_connection
        /* qcache */
        MYSQLND_QCACHE  *qcache;
 
-       MYSQLND_MEMORY_POOL * result_set_memory_pool;
-
        /* stats */
        MYSQLND_STATS   stats;
 
@@ -490,7 +523,7 @@ struct mysqlnd_field_hash_key
 #if PHP_MAJOR_VERSION >= 6
        zstr                    ustr;
        unsigned int    ulen;
-#endif 
+#endif
 };
 
 
@@ -578,7 +611,7 @@ struct st_mysqlnd_res
 
        /*
          Column lengths of current row - both buffered and unbuffered.
-         For buffered results it duplicates the data found in **data 
+         For buffered results it duplicates the data found in **data
        */
        unsigned long                   *lengths;
 
@@ -586,6 +619,8 @@ struct st_mysqlnd_res
 
        /* zval cache */
        MYSQLND_THD_ZVAL_PCACHE *zval_cache;
+
+       MYSQLND_MEMORY_POOL * result_set_memory_pool;
 };
 
 
index ea77bdc0bf2b0a2be3d5792ab98d39f7a74943ee..77719f69a9b32221ca003e0d9b9b9c0e7ac07d56 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
   +----------------------------------------------------------------------+
   | PHP Version 6                                                        |
@@ -29,6 +30,9 @@
 #include "ext/standard/sha1.h"
 #include "php_network.h"
 #include "zend_ini.h"
+#ifdef MYSQLND_COMPRESSION_ENABLED
+#include <zlib.h>
+#endif
 
 #ifndef PHP_WIN32
 #include <netinet/tcp.h>
 #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], \
@@ -83,7 +85,7 @@ char * mysqlnd_read_header_name       = "mysqlnd_read_header";
 char * mysqlnd_read_body_name  = "mysqlnd_read_body";
 
 
-/* {{{ mysqlnd_command_to_text 
+/* {{{ mysqlnd_command_to_text
  */
 const char * const mysqlnd_command_to_text[COM_END] =
 {
@@ -128,7 +130,7 @@ static enum_mysqlnd_collected_stats packet_type_to_statistic_packet_count[PROT_L
 };
 
 
-/* {{{ php_mysqlnd_net_field_length 
+/* {{{ php_mysqlnd_net_field_length
    Get next field's length */
 unsigned long php_mysqlnd_net_field_length(zend_uchar **packet)
 {
@@ -157,7 +159,7 @@ unsigned long php_mysqlnd_net_field_length(zend_uchar **packet)
 /* }}} */
 
 
-/* {{{ php_mysqlnd_net_field_length_ll 
+/* {{{ php_mysqlnd_net_field_length_ll
    Get next field's length */
 uint64_t php_mysqlnd_net_field_length_ll(zend_uchar **packet)
 {
@@ -212,6 +214,72 @@ zend_uchar *php_mysqlnd_net_store_length(zend_uchar *packet, uint64_t length)
 /* }}} */
 
 
+#ifdef MYSQLND_COMPRESSION_ENABLED
+/* {{{ php_mysqlnd_read_buffer_is_empty */
+static zend_bool
+php_mysqlnd_read_buffer_is_empty(MYSQLND_READ_BUFFER * buffer)
+{
+       return buffer->len? FALSE:TRUE;
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_read_buffer_read */
+static void
+php_mysqlnd_read_buffer_read(MYSQLND_READ_BUFFER * buffer, size_t count, zend_uchar * dest)
+{
+       if (buffer->len >= count) {
+               memcpy(dest, buffer->data + buffer->offset, count);
+               buffer->offset += count;
+               buffer->len -= count;
+       }
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_read_buffer_bytes_left */
+static size_t
+php_mysqlnd_read_buffer_bytes_left(MYSQLND_READ_BUFFER * buffer)
+{
+       return buffer->len;
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_read_buffer_free */
+static void
+php_mysqlnd_read_buffer_free(MYSQLND_READ_BUFFER ** buffer TSRMLS_DC)
+{
+       DBG_ENTER("php_mysqlnd_read_buffer_free");
+       if (*buffer) {
+               mnd_efree((*buffer)->data);
+               mnd_efree(*buffer);
+               *buffer = NULL;
+       }
+       DBG_VOID_RETURN;
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_create_read_buffer */
+static MYSQLND_READ_BUFFER *
+mysqlnd_create_read_buffer(size_t count TSRMLS_DC)
+{
+       MYSQLND_READ_BUFFER * ret = mnd_emalloc(sizeof(MYSQLND_READ_BUFFER));
+       DBG_ENTER("mysqlnd_create_read_buffer");
+       ret->is_empty = php_mysqlnd_read_buffer_is_empty;
+       ret->read = php_mysqlnd_read_buffer_read;
+       ret->bytes_left = php_mysqlnd_read_buffer_bytes_left;
+       ret->free = php_mysqlnd_read_buffer_free;
+       ret->data = mnd_emalloc(count);
+       ret->size = ret->len = count;
+       ret->offset = 0;
+       DBG_RETURN(ret);
+}
+/* }}} */
+#endif
+
+
 /* {{{ php_mysqlnd_consume_uneaten_data */
 #ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
 size_t php_mysqlnd_consume_uneaten_data(MYSQLND * const conn, enum php_mysqlnd_server_command cmd TSRMLS_DC)
@@ -261,10 +329,10 @@ size_t php_mysqlnd_consume_uneaten_data(MYSQLND * const conn, enum php_mysqlnd_s
 
 
 /* {{{ php_mysqlnd_read_error_from_line */
-static
-enum_func_status php_mysqlnd_read_error_from_line(zend_uchar *buf, size_t buf_len,
-                                                                                                 char *error, int error_buf_len,
-                                                                                                 unsigned int *error_no, char *sqlstate TSRMLS_DC)
+static enum_func_status
+php_mysqlnd_read_error_from_line(zend_uchar *buf, size_t buf_len,
+                                                               char *error, int error_buf_len,
+                                                               unsigned int *error_no, char *sqlstate TSRMLS_DC)
 {
        zend_uchar *p = buf;
        int error_msg_len= 0;
@@ -288,9 +356,9 @@ enum_func_status php_mysqlnd_read_error_from_line(zend_uchar *buf, size_t buf_le
        }
        sqlstate[MYSQLND_SQLSTATE_LENGTH] = '\0';
        error[error_msg_len]= '\0';
-       
+
        DBG_RETURN(FAIL);
-} 
+}
 /* }}} */
 
 
@@ -315,6 +383,17 @@ int mysqlnd_set_sock_no_delay(php_stream *stream)
 /* }}} */
 
 
+/* {{{ mysqlnd_stream_write */
+size_t mysqlnd_stream_write(MYSQLND * const conn, const zend_uchar * const buf, size_t count TSRMLS_DC)
+{
+       size_t ret;
+       DBG_ENTER("mysqlnd_stream_write");
+       ret = php_stream_write(conn->net.stream, (char *)buf, count);
+       DBG_RETURN(ret);
+}
+/* }}} */
+
+
 /* We assume that MYSQLND_HEADER_SIZE is 4 bytes !! */
 #define STORE_HEADER_SIZE(safe_storage, buffer)  int4store((safe_storage), (*(uint32_t *)(buffer)))
 #define RESTORE_HEADER_SIZE(buffer, safe_storage) STORE_HEADER_SIZE((safe_storage), (buffer))
@@ -338,32 +417,146 @@ size_t mysqlnd_stream_write_w_header(MYSQLND * const conn, char * const buf, siz
        size_t old_chunk_size = net->stream->chunk_size;
        size_t ret, left = count, packets_sent = 1;
        zend_uchar *p = (zend_uchar *) buf;
+       zend_uchar * compress_buf = NULL;
+       size_t comp_buf_size = 0;
 
        DBG_ENTER("mysqlnd_stream_write_w_header");
-       DBG_INF_FMT("conn=%llu count=%lu", conn->thread_id, count);
+       DBG_INF_FMT("conn=%llu count=%lu compression=%d", conn->thread_id, count, net->compressed);
 
        net->stream->chunk_size = MYSQLND_MAX_PACKET_SIZE;
 
+       if (net->compressed == TRUE) {
+               comp_buf_size = MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE + MIN(left, MYSQLND_MAX_PACKET_SIZE);
+               DBG_INF_FMT("compress_buf_size=%d", comp_buf_size);
+               compress_buf = emalloc(comp_buf_size);
+       }
+
        while (left > MYSQLND_MAX_PACKET_SIZE) {
-               STORE_HEADER_SIZE(safe_storage, p);
-               int3store(p, MYSQLND_MAX_PACKET_SIZE);
-               int1store(p + 3, net->packet_no);
+#ifdef MYSQLND_COMPRESSION_ENABLED
+
+               if (net->compressed == TRUE) {
+
+                       /* here we need to compress the data and then write it, first comes the compressed header */
+                       uLong tmp_complen = MYSQLND_MAX_PACKET_SIZE;
+                       size_t payload_size;
+                       zend_uchar * uncompressed_payload = p; /* should include the header */
+                       int res;
+
+                       STORE_HEADER_SIZE(safe_storage, uncompressed_payload);
+                       int3store(uncompressed_payload, MYSQLND_MAX_PACKET_SIZE);
+                       int1store(uncompressed_payload + 3, net->packet_no);
+
+                       DBG_INF_FMT("compress(%p, %p, %p, %d)", (compress_buf + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE), &tmp_complen, p, MYSQLND_MAX_PACKET_SIZE + MYSQLND_HEADER_SIZE);
+                       res = compress((compress_buf + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE), &tmp_complen, uncompressed_payload, MYSQLND_MAX_PACKET_SIZE + MYSQLND_HEADER_SIZE);
+                       if (res == Z_OK) {
+                               DBG_INF_FMT("compression successful. compressed size=%d", tmp_complen);
+                               int3store(compress_buf + MYSQLND_HEADER_SIZE, MYSQLND_MAX_PACKET_SIZE + MYSQLND_HEADER_SIZE);
+                               payload_size = tmp_complen;
+                       } else {
+                               DBG_INF_FMT("compression NOT successful. error=%d Z_OK=%d Z_BUF_ERROR=%d Z_MEM_ERROR=%d", res, Z_OK, Z_BUF_ERROR, Z_MEM_ERROR);
+                               int3store(compress_buf + MYSQLND_HEADER_SIZE, 0);
+                               memcpy(compress_buf + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, uncompressed_payload, MYSQLND_MAX_PACKET_SIZE + MYSQLND_HEADER_SIZE);
+                               payload_size = MYSQLND_MAX_PACKET_SIZE + MYSQLND_HEADER_SIZE;
+                       }
+                       RESTORE_HEADER_SIZE(uncompressed_payload, safe_storage);
+
+                       int3store(compress_buf, payload_size);
+                       int1store(compress_buf + 3, net->packet_no);
+                       DBG_INF_FMT("writing %d bytes to the network", payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE);
+                       ret = conn->net.stream_write(conn, compress_buf, payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE TSRMLS_CC);
+                       net->compressed_envelope_packet_no++;
+               } else
+#endif /* MYSQLND_COMPRESSION_ENABLED */
+               {
+                       DBG_INF("no compression");
+                       STORE_HEADER_SIZE(safe_storage, p);
+                       int3store(p, MYSQLND_MAX_PACKET_SIZE);
+                       int1store(p + 3, net->packet_no);
+                       ret = conn->net.stream_write(conn, p, MYSQLND_MAX_PACKET_SIZE + MYSQLND_HEADER_SIZE TSRMLS_CC);
+                       RESTORE_HEADER_SIZE(p, safe_storage);
+                       net->compressed_envelope_packet_no++;
+               }
                net->packet_no++;
-               ret = php_stream_write(net->stream, (char *)p, MYSQLND_MAX_PACKET_SIZE + MYSQLND_HEADER_SIZE);
-               RESTORE_HEADER_SIZE(p, safe_storage);
 
                p += MYSQLND_MAX_PACKET_SIZE;
                left -= MYSQLND_MAX_PACKET_SIZE;
 
                packets_sent++;
        }
+
+       DBG_INF_FMT("packet_size=%d packet_no=%d", left, net->packet_no);
        /* Even for zero size payload we have to send a packet */
-       STORE_HEADER_SIZE(safe_storage, p);
-       int3store(p, left);
-       int1store(p + 3, net->packet_no);
+
+#ifdef MYSQLND_COMPRESSION_ENABLED
+       if (net->compressed == TRUE) {
+               /* here we need to compress the data and then write it, first comes the compressed header */
+               uLong tmp_complen = left;
+               size_t payload_size;
+               zend_uchar * uncompressed_payload = p; /* should include the header */
+               int res = Z_BUF_ERROR;
+
+               STORE_HEADER_SIZE(safe_storage, uncompressed_payload);
+               int3store(uncompressed_payload, left);
+               int1store(uncompressed_payload + 3, net->packet_no);
+               if ((left + MYSQLND_HEADER_SIZE) > MYSQLND_MIN_COMPRESS_LEN) {
+                       DBG_INF_FMT("compress(%p, %p, %p, %d)", (compress_buf + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE), &tmp_complen, p, left + MYSQLND_HEADER_SIZE);
+                       res = compress((compress_buf + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE), &tmp_complen, uncompressed_payload, left + MYSQLND_HEADER_SIZE);
+                       if (res == Z_OK) {
+                               DBG_INF_FMT("compression successful. compressed size=%d", tmp_complen);
+                               int3store(compress_buf + MYSQLND_HEADER_SIZE, left + MYSQLND_HEADER_SIZE);
+                               payload_size = tmp_complen;
+                       }
+               } else {
+                       DBG_INF("Too short for compression");
+               }
+               if (res != Z_OK) {
+                       DBG_INF_FMT("compression NOT successful. error=%d Z_OK=%d Z_BUF_ERROR=%d Z_MEM_ERROR=%d", res, Z_OK, Z_BUF_ERROR, Z_MEM_ERROR);
+                       int3store(compress_buf + MYSQLND_HEADER_SIZE, 0);
+                       memcpy(compress_buf + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, uncompressed_payload, left + MYSQLND_HEADER_SIZE);
+                       payload_size = left + MYSQLND_HEADER_SIZE;
+               }
+               RESTORE_HEADER_SIZE(uncompressed_payload, safe_storage);
+
+               int3store(compress_buf, payload_size);
+               int1store(compress_buf + 3, net->packet_no);
+               DBG_INF_FMT("writing %d bytes to the network", payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE);
+               ret = conn->net.stream_write(conn, compress_buf, payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE TSRMLS_CC);
+
+               net->compressed_envelope_packet_no++;
+  #if WHEN_WE_NEED_TO_CHECK_WHETHER_COMPRESSION_WORKS_CORRECTLY
+               if (res == Z_OK) {
+                       size_t decompressed_size = left + MYSQLND_HEADER_SIZE;
+                       uLongf tmp_complen2 = decompressed_size;
+                       zend_uchar * decompressed_data = malloc(decompressed_size);
+                       int error = uncompress(decompressed_data, &tmp_complen2, compress_buf + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, payload_size);
+                       if (error == Z_OK) {
+                               int i;
+                               DBG_INF("success decompressing");
+                               for (i = 0 ; i < decompressed_size; i++) {
+                                       if (i && (i % 30 == 0)) {
+                                               printf("\n\t\t");
+                                       }
+                                       printf("%.2X ", (int)*((char*)&(decompressed_data[i])));
+                                       DBG_INF_FMT("%.2X ", (int)*((char*)&(decompressed_data[i])));
+                               }
+                       } else {
+                               DBG_INF("error decompressing");
+                       }
+                       free(decompressed_data);
+               }
+  #endif /* WHEN_WE_NEED_TO_CHECK_WHETHER_COMPRESSION_WORKS_CORRECTLY */
+
+       } else
+#endif /* MYSQLND_COMPRESSION_ENABLED */
+       {
+               DBG_INF("no compression");
+               STORE_HEADER_SIZE(safe_storage, p);
+               int3store(p, left);
+               int1store(p + 3, net->packet_no);
+               ret = conn->net.stream_write(conn, p, left + MYSQLND_HEADER_SIZE TSRMLS_CC);
+               RESTORE_HEADER_SIZE(p, safe_storage);
+       }
        net->packet_no++;
-       ret = php_stream_write(net->stream, (char *)p, left + MYSQLND_HEADER_SIZE);
-       RESTORE_HEADER_SIZE(p, safe_storage);
 
        if (!ret) {
                DBG_ERR_FMT("Can't %u send bytes", count);
@@ -377,126 +570,198 @@ size_t mysqlnd_stream_write_w_header(MYSQLND * const conn, char * const buf, siz
                        STAT_PACKETS_SENT, packets_sent);
 
        net->stream->chunk_size = old_chunk_size;
-
+       if (compress_buf) {
+               efree(compress_buf);
+       }
        DBG_RETURN(ret);
 }
 /* }}} */
 
 
-/* {{{ mysqlnd_stream_write_w_command */
-#if USE_CORK && defined(TCP_CORK)
-static
-size_t mysqlnd_stream_write_w_command(MYSQLND * const conn, enum php_mysqlnd_server_command command,
-                                                                         const char * const buf, size_t count TSRMLS_DC)
+/* {{{ mysqlnd_read_from_stream */
+enum_func_status
+mysqlnd_read_from_stream(MYSQLND * conn, zend_uchar * buffer, size_t count TSRMLS_DC)
 {
-       zend_uchar safe_buf[((MYSQLND_HEADER_SIZE) + (sizeof(zend_uchar)) - 1) / (sizeof(zend_uchar))];
-       zend_uchar *safe_storage = (char *) &safe_buf;
-       MYSQLND_NET *net = &conn->net;
-       size_t old_chunk_size = net->stream->chunk_size;
-       size_t ret, left = count, header_len = MYSQLND_HEADER_SIZE + 1, packets_sent = 1;
-       const zend_uchar *p = (zend_uchar *) buf;
-       zend_bool command_sent = FALSE;
-       int corked = 1;
+       size_t to_read = count, ret;
+       size_t old_chunk_size = conn->net.stream->chunk_size;
+       DBG_ENTER("mysqlnd_read_from_stream");
+       DBG_INF_FMT("count=%u", count);
+       conn->net.stream->chunk_size = MIN(to_read, conn->options.net_read_buffer_size);
+       while (to_read) {
+               if (!(ret = php_stream_read(conn->net.stream, (char *) buffer, to_read))) {
+                       DBG_ERR_FMT("Error while reading header from socket");
+                       DBG_RETURN(FAIL);
+               }
+               buffer += ret;
+               to_read -= ret;
+       }
+       MYSQLND_INC_CONN_STATISTIC_W_VALUE(&conn->stats, STAT_BYTES_RECEIVED, count);
+       conn->net.stream->chunk_size = old_chunk_size;
+       DBG_RETURN(PASS);
+}
+/* }}} */
 
-       DBG_ENTER("mysqlnd_stream_write_w_command");
 
-       net->stream->chunk_size = MYSQLND_MAX_PACKET_SIZE;
+#ifdef MYSQLND_COMPRESSION_ENABLED
+/* {{{ mysqlnd_read_compressed_packet_from_stream_and_fill_read_buffer */
+static enum_func_status
+mysqlnd_read_compressed_packet_from_stream_and_fill_read_buffer(MYSQLND * conn, size_t net_payload_size TSRMLS_DC)
+{
+       MYSQLND_NET * net = &conn->net;
+       size_t decompressed_size;
+       enum_func_status ret = PASS;
+       zend_uchar * compressed_data = NULL;
+       zend_uchar comp_header[COMPRESSED_HEADER_SIZE];
+       DBG_ENTER("mysqlnd_read_compressed_packet_from_stream_and_fill_read_buffer");
 
-       setsockopt(((php_netstream_data_t*)net->stream->abstract)->socket,
-                               IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
+       /* Read the compressed header */
+       if (FAIL == conn->net.stream_read(conn, comp_header, COMPRESSED_HEADER_SIZE TSRMLS_CC)) {
+               DBG_RETURN(FAIL);
+       }
+       decompressed_size = uint3korr(comp_header);
 
-       int1store(safe_storage + MYSQLND_HEADER_SIZE, command);
-       while (left > MYSQLND_MAX_PACKET_SIZE) {
-               size_t body_size = MYSQLND_MAX_PACKET_SIZE;
+       /* When decompressed_size is 0, then the data is not compressed, and we have wasted 3 bytes */
+       /* we need to decompress the data */
 
-               int3store(safe_storage, MYSQLND_MAX_PACKET_SIZE);
-               int1store(safe_storage + 3, net->packet_no);
-               net->packet_no++;
-               
-               ret = php_stream_write(net->stream, (char *)safe_storage, header_len);
-               if (command_sent == FALSE) {
-                       --header_len;
-                       /* Sent one byte less*/
-                       --body_size;
-                       command_sent = TRUE;
+       if (decompressed_size) {
+               int error;
+               uLongf tmp_complen = decompressed_size;
+               compressed_data = emalloc(net_payload_size);
+               if (FAIL == conn->net.stream_read(conn, compressed_data, net_payload_size TSRMLS_CC)) {
+                       ret = FAIL;
+                       goto end;
                }
 
-               ret = php_stream_write(net->stream, (char *)p, body_size);
-
-               p += body_size;
-               left -= body_size;
+               net->uncompressed_data = mysqlnd_create_read_buffer(decompressed_size TSRMLS_CC);
+               error = uncompress(net->uncompressed_data->data, &tmp_complen, compressed_data, net_payload_size);
 
-               packets_sent++;
+               DBG_INF_FMT("compressed data: decomp_len=%d compressed_size=%d", decompressed_size, net_payload_size);
+               if (error != Z_OK) {
+                       DBG_ERR_FMT("Can't uncompress packet, error: %d", error);
+                       ret = FAIL;
+                       goto end;
+               }
+       } else {
+               DBG_INF_FMT("The server decided not to compress the data. Our job is easy. Copying %u bytes", net_payload_size);
+               net->uncompressed_data = mysqlnd_create_read_buffer(net_payload_size TSRMLS_CC);
+               if (FAIL == conn->net.stream_read(conn, net->uncompressed_data->data, net_payload_size TSRMLS_CC)) {
+                       ret = FAIL;
+                       goto end;
+               }
        }
-       /* Even for zero size payload we have to send a packet */
-       int3store(safe_storage, header_len == MYSQLND_HEADER_SIZE? left:left+1);
-       int1store(safe_storage + 3, net->packet_no);
-       net->packet_no++;
-       
-       ret = php_stream_write(net->stream, (char *)safe_storage, header_len);
-
-       if (left) {
-               ret = php_stream_write(net->stream, (char *)p, left);
+end:
+       if (compressed_data) {
+               efree(compressed_data);
        }
-       corked = 0;
-       setsockopt(((php_netstream_data_t*)net->stream->abstract)->socket,
-                               IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
+       DBG_RETURN(ret);
+}
+#endif /* MYSQLND_COMPRESSION_ENABLED */
 
-       MYSQLND_INC_CONN_STATISTIC_W_VALUE3(&conn->stats, STAT_BYTES_SENT,
-                               count + packets_sent * MYSQLND_HEADER_SIZE);
-                               STAT_PROTOCOL_OVERHEAD_OUT, packets_sent * MYSQLND_HEADER_SIZE);
-                               STAT_PACKETS_SENT, packets_sent);
 
-       net->stream->chunk_size = old_chunk_size;
+/* {{{ mysqlnd_real_read */
+static enum_func_status
+mysqlnd_real_read(MYSQLND * conn, zend_uchar * buffer, size_t count TSRMLS_DC)
+{
+       size_t to_read = count;
+       zend_uchar * p = buffer;
+
+       DBG_ENTER("mysqlnd_real_read");
+#ifdef MYSQLND_COMPRESSION_ENABLED
+       if (conn->net.compressed) {
+               MYSQLND_NET * net = &conn->net;
+               if (net->uncompressed_data) {
+                       size_t to_read_from_buffer = MIN(net->uncompressed_data->bytes_left(net->uncompressed_data), to_read);
+                       DBG_INF_FMT("reading %u from uncompressed_data buffer", to_read_from_buffer);
+                       if (to_read_from_buffer) {
+                               net->uncompressed_data->read(net->uncompressed_data, to_read_from_buffer, (zend_uchar *) p);
+                               p += to_read_from_buffer;
+                               to_read -= to_read_from_buffer;
+                       }
+                       DBG_INF_FMT("left %u to read", to_read);
+                       if (TRUE == net->uncompressed_data->is_empty(net->uncompressed_data)) {
+                               /* Everything was consumed. This should never happen here, but for security */
+                               net->uncompressed_data->free(&net->uncompressed_data TSRMLS_CC);
+                       }
+               }
+               if (to_read) {
+                       zend_uchar net_header[MYSQLND_HEADER_SIZE];
+                       size_t net_payload_size;
+                       zend_uchar packet_no;
 
-       DBG_RETURN(ret);
-}
+                       if (FAIL == conn->net.stream_read(conn, net_header, MYSQLND_HEADER_SIZE TSRMLS_CC)) {
+                               DBG_RETURN(FAIL);
+                       }
+                       net_payload_size = uint3korr(net_header);
+                       packet_no = uint1korr(net_header + 3);
+                       if (net->compressed_envelope_packet_no != packet_no) {
+                               DBG_ERR_FMT("Transport level: packets out of order. Expected %d received %d. Packet size=%d",
+                                                       net->compressed_envelope_packet_no, packet_no, net_payload_size);
+
+                               php_error(E_WARNING, "Packets out of order. Expected %d received %d. Packet size="MYSQLND_SZ_T_SPEC,
+                                                 net->compressed_envelope_packet_no, packet_no, net_payload_size);
+#if 0
+                               *(int *) NULL = 0;
 #endif
+                               DBG_RETURN(FAIL);
+                       }
+                       net->compressed_envelope_packet_no++;
+#ifdef MYSQLND_DUMP_HEADER_N_BODY
+                       DBG_INF_FMT("HEADER: hwd_packet_no=%d size=%3d", packet_no, net_payload_size);
+#endif
+                       /* Now let's read from the wire, decompress it and fill the read buffer */
+                       mysqlnd_read_compressed_packet_from_stream_and_fill_read_buffer(conn, net_payload_size TSRMLS_CC);
+
+                       /*
+                         Now a bit of recursion - read from the read buffer,
+                         if the data which we have just read from the wire
+                         is not enough, then the recursive call will try to
+                         satisfy it until it is satisfied.
+                       */
+                       DBG_RETURN(mysqlnd_real_read(conn, p, to_read TSRMLS_CC));
+               }
+               DBG_RETURN(PASS);
+       }
+#endif /* MYSQLND_COMPRESSION_ENABLED */
+       DBG_RETURN(conn->net.stream_read(conn, p, to_read TSRMLS_CC));
+}
 /* }}} */
 
 
 /* {{{ mysqlnd_read_header */
 static enum_func_status
-mysqlnd_read_header(MYSQLND *conn, mysqlnd_packet_header *header TSRMLS_DC)
+mysqlnd_read_header(MYSQLND * conn, mysqlnd_packet_header * header TSRMLS_DC)
 {
        MYSQLND_NET *net = &conn->net;
-       char buffer[MYSQLND_HEADER_SIZE];
-       char *p = buffer;
-       int to_read = MYSQLND_HEADER_SIZE, ret;
-
-       DBG_ENTER(mysqlnd_read_header_name);
+       zend_uchar buffer[MYSQLND_HEADER_SIZE];
 
-       do {
-               if (!(ret= php_stream_read(net->stream, p, to_read))) {
-                       DBG_ERR_FMT("Error while reading header from socket");
-                       return FAIL;
-               }
-               p += ret;
-               to_read -= ret;
-       } while (to_read);
+       DBG_ENTER("mysqlnd_read_header_name");
+       DBG_INF_FMT("compressed=%d conn_id=%u", net->compressed, conn->thread_id);
+       if (FAIL == mysqlnd_real_read(conn, buffer, MYSQLND_HEADER_SIZE TSRMLS_CC)) {
+               DBG_RETURN(FAIL);
+       }
 
        header->size = uint3korr(buffer);
        header->packet_no = uint1korr(buffer + 3);
 
+#ifdef MYSQLND_DUMP_HEADER_N_BODY
+       DBG_INF_FMT("HEADER: prot_packet_no=%d size=%3d", header->packet_no, header->size);
+#endif
        MYSQLND_INC_CONN_STATISTIC_W_VALUE3(&conn->stats,
                                                        STAT_BYTES_RECEIVED, MYSQLND_HEADER_SIZE,
                                                        STAT_PROTOCOL_OVERHEAD_IN, MYSQLND_HEADER_SIZE,
                                                        STAT_PACKETS_RECEIVED, 1);
 
-       if (net->packet_no == header->packet_no) {
+       if (net->compressed || net->packet_no == header->packet_no) {
                /*
                  Have to increase the number, so we can send correct number back. It will
                  round at 255 as this is unsigned char. The server needs this for simple
                  flow control checking.
                */
                net->packet_no++;
-#ifdef MYSQLND_DUMP_HEADER_N_BODY
-               DBG_ERR_FMT("HEADER: packet_no=%d size=%3d", header->packet_no, header->size);
-#endif
                DBG_RETURN(PASS);
        }
 
-       DBG_ERR_FMT("Packets out of order. Expected %d received %d. Packet size=%d",
+       DBG_ERR_FMT("Logical link: packets out of order. Expected %d received %d. Packet size=%d",
                                net->packet_no, header->packet_no, header->size);
 
        php_error(E_WARNING, "Packets out of order. Expected %d received %d. Packet size="MYSQLND_SZ_T_SPEC,
@@ -507,52 +772,15 @@ mysqlnd_read_header(MYSQLND *conn, mysqlnd_packet_header *header TSRMLS_DC)
 
 
 /* {{{ mysqlnd_read_body */
-static
-size_t mysqlnd_read_body(MYSQLND *conn, zend_uchar *buf, size_t size TSRMLS_DC)
+static enum_func_status
+mysqlnd_read_body(MYSQLND *conn, mysqlnd_packet_header * header, zend_uchar * store_buf TSRMLS_DC)
 {
-       size_t ret;
-       char *p = (char *)buf;
-       unsigned int iter = 0;
        MYSQLND_NET *net = &conn->net;
-       size_t old_chunk_size = net->stream->chunk_size;
 
        DBG_ENTER(mysqlnd_read_body_name);
-       DBG_INF_FMT("chunk_size=%d", net->stream->chunk_size);
-
-       net->stream->chunk_size = MIN(size, conn->options.net_read_buffer_size);
-       do {
-               size -= (ret = php_stream_read(net->stream, p, size));
-               if (size > 0 || iter++) {
-                       DBG_INF_FMT("read=%d buf=%p p=%p chunk_size=%d left=%d",
-                                               ret, buf, p , net->stream->chunk_size, size);
-               }
-               p += ret;
-       } while (size > 0);
-
-       MYSQLND_INC_CONN_STATISTIC_W_VALUE(&conn->stats, STAT_BYTES_RECEIVED, p - (char*)buf);
-       net->stream->chunk_size = old_chunk_size;
+       DBG_INF_FMT("chunk_size=%d compression=%d", net->stream->chunk_size, net->compressed);
 
-#ifdef MYSQLND_DUMP_HEADER_N_BODY_FULL
-       {
-               unsigned int i;
-               DBG_INF_FMT("BODY: requested=%d last_read=%3d", p - (char*)buf, ret);
-               for (i = 0 ; i < p - (char*)buf; i++) {
-                       if (i && (i % 30 == 0)) {
-                               printf("\n\t\t");
-                       }
-                       printf("[%c] ", *(char *)(&(buf[i])));
-               }
-               for (i = 0 ; i < p - (char*)buf; i++) {
-                       if (i && (i % 30 == 0)) {
-                               printf("\n\t\t");
-                       }
-                       printf("%.2X ", (int)*((char*)&(buf[i])));
-               }
-               php_printf("\n\t\t\t-=-=-=-=-\n");
-       }
-#endif
-
-       DBG_RETURN(p - (char*)buf);
+       DBG_RETURN(mysqlnd_real_read(conn, store_buf, header->size TSRMLS_CC));
 }
 /* }}} */
 
@@ -561,7 +789,7 @@ size_t mysqlnd_read_body(MYSQLND *conn, zend_uchar *buf, size_t size TSRMLS_DC)
 static enum_func_status
 php_mysqlnd_greet_read(void *_packet, MYSQLND *conn TSRMLS_DC)
 {
-       zend_uchar buf[512];
+       zend_uchar buf[2048];
        zend_uchar *p = buf;
        zend_uchar *begin = buf;
        php_mysql_packet_greet *packet= (php_mysql_packet_greet *) _packet;
@@ -678,7 +906,7 @@ void php_mysqlnd_scramble(zend_uchar * const buffer, const zend_uchar * const sc
        PHP_SHA1_CTX context;
        zend_uchar sha1[SHA1_MAX_LENGTH];
        zend_uchar sha2[SHA1_MAX_LENGTH];
-       
+
 
        /* Phase 1: hash password */
        PHP_SHA1Init(&context);
@@ -722,7 +950,7 @@ size_t php_mysqlnd_auth_write(void *_packet, MYSQLND *conn TSRMLS_DC)
        if (PG(open_basedir) && strlen(PG(open_basedir))) {
                packet->client_flags ^= CLIENT_LOCAL_FILES;
        }
-       
+
        int4store(p, packet->client_flags);
        p+= 4;
 
@@ -733,7 +961,7 @@ size_t php_mysqlnd_auth_write(void *_packet, MYSQLND *conn TSRMLS_DC)
        p++;
 
        memset(p, 0, 23); /* filler */
-       p+= 23; 
+       p+= 23;
 
        len= strlen(packet->user);
        memcpy(p, packet->user, len);
@@ -765,6 +993,7 @@ size_t php_mysqlnd_auth_write(void *_packet, MYSQLND *conn TSRMLS_DC)
 }
 /* }}} */
 
+
 /* {{{ php_mysqlnd_auth_free_mem */
 static
 void php_mysqlnd_auth_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
@@ -776,11 +1005,15 @@ void php_mysqlnd_auth_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
 /* }}} */
 
 
+#define OK_BUFFER_SIZE 2048
+
 /* {{{ php_mysqlnd_ok_read */
 static enum_func_status
 php_mysqlnd_ok_read(void *_packet, MYSQLND *conn TSRMLS_DC)
 {
-       zend_uchar buf[1024];
+       zend_uchar local_buf[OK_BUFFER_SIZE];
+       size_t buf_len = conn->net.cmd_buffer.buffer? conn->net.cmd_buffer.length : OK_BUFFER_SIZE;
+       zend_uchar *buf = conn->net.cmd_buffer.buffer? (zend_uchar *) conn->net.cmd_buffer.buffer : local_buf;
        zend_uchar *p = buf;
        zend_uchar *begin = buf;
        unsigned long i;
@@ -788,7 +1021,7 @@ php_mysqlnd_ok_read(void *_packet, MYSQLND *conn TSRMLS_DC)
 
        DBG_ENTER("php_mysqlnd_ok_read");
 
-       PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "OK", PROT_OK_PACKET);
+       PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "OK", PROT_OK_PACKET);
 
        /* Should be always 0x0 or 0xFF for error */
        packet->field_count = uint1korr(p);
@@ -813,7 +1046,7 @@ php_mysqlnd_ok_read(void *_packet, MYSQLND *conn TSRMLS_DC)
 
        /* There is a message */
        if (packet->header.size > p - buf && (i = php_mysqlnd_net_field_length(&p))) {
-               packet->message = estrndup((char *)p, MIN(i, sizeof(buf) - (p - buf)));
+               packet->message = estrndup((char *)p, MIN(i, buf_len - (p - begin)));
                packet->message_len = i;
        } else {
                packet->message = NULL;
@@ -861,13 +1094,14 @@ php_mysqlnd_eof_read(void *_packet, MYSQLND *conn TSRMLS_DC)
          Error : error_code + '#' + sqlstate + MYSQLND_ERRMSG_SIZE
        */
        php_mysql_packet_eof *packet= (php_mysql_packet_eof *) _packet;
-       zend_uchar buf[5 + 10 + sizeof(packet->sqlstate) + sizeof(packet->error)];
+       size_t buf_len = conn->net.cmd_buffer.length;
+       zend_uchar *buf = (zend_uchar *) conn->net.cmd_buffer.buffer;
        zend_uchar *p = buf;
        zend_uchar *begin = buf;
 
        DBG_ENTER("php_mysqlnd_eof_read");
 
-       PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "EOF", PROT_EOF_PACKET);
+       PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "EOF", PROT_EOF_PACKET);
 
        /* Should be always 0xFE */
        packet->field_count = uint1korr(p);
@@ -901,7 +1135,7 @@ php_mysqlnd_eof_read(void *_packet, MYSQLND *conn TSRMLS_DC)
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "EOF packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
                                                 p - begin - packet->header.size);
        }
-       
+
        DBG_INF_FMT("EOF packet: fields=%d status=%d warnings=%d",
                                packet->field_count, packet->server_status, packet->warning_count);
 
@@ -936,13 +1170,14 @@ size_t php_mysqlnd_cmd_write(void *_packet, MYSQLND *conn TSRMLS_DC)
          Every command starts a new TX and packet numbers are reset to 0.
        */
        net->packet_no = 0;
+       net->compressed_envelope_packet_no = 0; /* this is for the response */
 
        if (error_reporting) {
                EG(error_reporting) = 0;
        }
 
        MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_PACKETS_SENT_CMD);
-       
+
 #ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
        php_mysqlnd_consume_uneaten_data(conn, packet->command TSRMLS_CC);
 #endif
@@ -953,10 +1188,6 @@ size_t php_mysqlnd_cmd_write(void *_packet, MYSQLND *conn TSRMLS_DC)
                int1store(buffer + MYSQLND_HEADER_SIZE, packet->command);
                written = mysqlnd_stream_write_w_header(conn, buffer, 1 TSRMLS_CC);
        } else {
-#if USE_CORK && defined(TCP_CORK)
-               written = mysqlnd_stream_write_w_command(conn, packet->command, packet->argument,
-                                                                                                packet->arg_len TSRMLS_CC));
-#else
                size_t tmp_len = packet->arg_len + 1 + MYSQLND_HEADER_SIZE, ret;
                zend_uchar *tmp, *p;
                tmp = (tmp_len > net->cmd_buffer.length)? mnd_emalloc(tmp_len):net->cmd_buffer.buffer;
@@ -973,7 +1204,6 @@ size_t php_mysqlnd_cmd_write(void *_packet, MYSQLND *conn TSRMLS_DC)
                        mnd_efree(tmp);
                }
                written = ret;
-#endif
        }
        if (error_reporting) {
                /* restore error reporting */
@@ -999,7 +1229,8 @@ void php_mysqlnd_cmd_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
 static enum_func_status
 php_mysqlnd_rset_header_read(void *_packet, MYSQLND *conn TSRMLS_DC)
 {
-       zend_uchar buf[1024];
+       size_t buf_len = conn->net.cmd_buffer.length;
+       zend_uchar *buf = (zend_uchar *) conn->net.cmd_buffer.buffer;
        zend_uchar *p = buf;
        zend_uchar *begin = buf;
        size_t len;
@@ -1007,7 +1238,7 @@ php_mysqlnd_rset_header_read(void *_packet, MYSQLND *conn TSRMLS_DC)
 
        DBG_ENTER("php_mysqlnd_rset_header_read");
 
-       PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "resultset header", PROT_RSET_HEADER_PACKET);
+       PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "resultset header", PROT_RSET_HEADER_PACKET);
 
        /*
          Don't increment. First byte is 0xFF on error, but otherwise is starting byte
@@ -1076,6 +1307,7 @@ php_mysqlnd_rset_header_read(void *_packet, MYSQLND *conn TSRMLS_DC)
 static
 void php_mysqlnd_rset_header_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
 {
+       DBG_ENTER("php_mysqlnd_rset_header_free_mem");
        php_mysql_packet_rset_header *p= (php_mysql_packet_rset_header *) _packet;
        if (p->info_or_local_file) {
                mnd_efree(p->info_or_local_file);
@@ -1084,6 +1316,7 @@ void php_mysqlnd_rset_header_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
        if (!alloca) {
                mnd_pefree(p, p->header.persistent);
        }
+       DBG_VOID_RETURN;
 }
 /* }}} */
 
@@ -1110,11 +1343,11 @@ php_mysqlnd_rset_field_read(void *_packet, MYSQLND *conn TSRMLS_DC)
 {
        /* Should be enough for the metadata of a single row */
        php_mysql_packet_res_field *packet= (php_mysql_packet_res_field *) _packet;
+       size_t buf_len = conn->net.cmd_buffer.length, total_len = 0;
        zend_uchar *buf = (zend_uchar *) conn->net.cmd_buffer.buffer;
        zend_uchar *p = buf;
        zend_uchar *begin = buf;
        char *root_ptr;
-       size_t buf_len = conn->net.cmd_buffer.length, total_len = 0;
        unsigned long len;
        MYSQLND_FIELD *meta;
        unsigned int i, field_count = sizeof(rset_field_offsets)/sizeof(size_t);
@@ -1289,7 +1522,8 @@ void php_mysqlnd_rset_field_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
 
 
 static enum_func_status
-php_mysqlnd_read_row_ex(MYSQLND *conn, MYSQLND_MEMORY_POOL_CHUNK **buffer,
+php_mysqlnd_read_row_ex(MYSQLND *conn, MYSQLND_MEMORY_POOL * result_set_memory_pool,
+                                               MYSQLND_MEMORY_POOL_CHUNK **buffer,
                                                uint64_t *data_size, zend_bool persistent_alloc,
                                                unsigned int prealloc_more_bytes TSRMLS_DC)
 {
@@ -1323,8 +1557,7 @@ php_mysqlnd_read_row_ex(MYSQLND *conn, MYSQLND_MEMORY_POOL_CHUNK **buffer,
                          We need a trailing \0 for the last string, in case of text-mode,
                          to be able to implement read-only variables. Thus, we add + 1.
                        */
-                       *buffer = conn->result_set_memory_pool->get_chunk(conn->result_set_memory_pool,
-                                                                                                                         *data_size + 1 TSRMLS_CC);
+                       *buffer = result_set_memory_pool->get_chunk(result_set_memory_pool, *data_size + 1 TSRMLS_CC);
                        p = (*buffer)->ptr;
                } else if (!first_iteration) {
                        /* Empty packet after MYSQLND_MAX_PACKET_SIZE packet. That's ok, break */
@@ -1343,10 +1576,9 @@ php_mysqlnd_read_row_ex(MYSQLND *conn, MYSQLND_MEMORY_POOL_CHUNK **buffer,
                        p = (*buffer)->ptr + (*data_size - header.size);
                }
 
-               if (!mysqlnd_read_body(conn, p, header.size TSRMLS_CC)) {
+               if ((ret = mysqlnd_read_body(conn, &header, p TSRMLS_CC))) {
                        DBG_ERR("Empty row packet body");
                        php_error(E_WARNING, "Empty row packet body");
-                       ret = FAIL;
                        break;
                }
 
@@ -1354,7 +1586,7 @@ php_mysqlnd_read_row_ex(MYSQLND *conn, MYSQLND_MEMORY_POOL_CHUNK **buffer,
                        break;
                }
        }
-       if (ret == FAIL) {
+       if (ret == FAIL && *buffer) {
                (*buffer)->free_chunk((*buffer), TRUE TSRMLS_CC);
                *buffer = NULL;
        }
@@ -1365,14 +1597,16 @@ php_mysqlnd_read_row_ex(MYSQLND *conn, MYSQLND_MEMORY_POOL_CHUNK **buffer,
 
 /* {{{ php_mysqlnd_rowp_read_binary_protocol */
 void php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
-                                                                                  unsigned int field_count, MYSQLND_FIELD *fields_metadata,
-                                                                                  MYSQLND *conn TSRMLS_DC)
+                                                                                unsigned int field_count, MYSQLND_FIELD *fields_metadata,
+                                                                                zend_bool persistent,
+                                                                                zend_bool as_unicode, zend_bool as_int_or_float,
+                                                                                MYSQLND_THD_ZVAL_PCACHE * zval_cache,
+                                                                                MYSQLND_STATS * stats TSRMLS_DC)
 {
        int i;
        zend_uchar *p = row_buffer->ptr;
        zend_uchar *null_ptr, bit;
        zval **current_field, **end_field, **start_field;
-       zend_bool as_unicode = conn->options.numeric_and_datetime_as_unicode;
 #ifdef USE_ZVAL_CACHE
        zend_bool allocated;
        void *obj;
@@ -1392,12 +1626,12 @@ void php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffe
        for (i = 0; current_field < end_field; current_field++, i++) {
 #ifdef USE_ZVAL_CACHE
                DBG_INF("Trying to use the zval cache");
-               obj = mysqlnd_palloc_get_zval(conn->zval_cache, &allocated TSRMLS_CC);
+               obj = mysqlnd_palloc_get_zval(zval_cache, &allocated TSRMLS_CC);
                if (allocated) {
                        *current_field = (zval *) obj;
                } else {
                        /* It's from the cache, so we can upcast here */
-                       *current_field = &((mysqlnd_zval *) obj)->zv;                   
+                       *current_field = &((mysqlnd_zval *) obj)->zv;
                        ((mysqlnd_zval *) obj)->point_type = MYSQLND_POINTS_EXT_BUFFER;
                }
 #else
@@ -1412,7 +1646,7 @@ void php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffe
                if (*null_ptr & bit) {
                        DBG_INF("It's null");
                        ZVAL_NULL(*current_field);
-                       MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_BINARY_TYPE_FETCHED_NULL);
+                       MYSQLND_INC_CONN_STATISTIC(stats, STAT_BINARY_TYPE_FETCHED_NULL);
                } else {
                        enum_mysqlnd_field_types type = fields_metadata[i].type;
                        mysqlnd_ps_fetch_functions[type].func(*current_field, &fields_metadata[i],
@@ -1449,8 +1683,8 @@ void php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffe
                                        case MYSQL_TYPE_STRING:         statistic = STAT_BINARY_TYPE_FETCHED_STRING; break;
                                        case MYSQL_TYPE_GEOMETRY:       statistic = STAT_BINARY_TYPE_FETCHED_GEOMETRY; break;
                                        default: statistic = STAT_BINARY_TYPE_FETCHED_OTHER; break;
-                               }                       
-                               MYSQLND_INC_CONN_STATISTIC(&conn->stats, statistic);
+                               }
+                               MYSQLND_INC_CONN_STATISTIC(stats, statistic);
                        }
                }
                if (!((bit<<=1) & 255)) {
@@ -1467,7 +1701,10 @@ void php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffe
 /* {{{ php_mysqlnd_rowp_read_text_protocol */
 void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
                                                                                 unsigned int field_count, MYSQLND_FIELD *fields_metadata,
-                                                                                MYSQLND *conn TSRMLS_DC)
+                                                                                zend_bool persistent,
+                                                                                zend_bool as_unicode, zend_bool as_int_or_float,
+                                                                                MYSQLND_THD_ZVAL_PCACHE * zval_cache,
+                                                                                MYSQLND_STATS * stats TSRMLS_DC)
 {
        int i;
        zend_bool last_field_was_string = FALSE;
@@ -1475,10 +1712,6 @@ void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
        zend_uchar *p = row_buffer->ptr;
        size_t data_size = row_buffer->app;
        zend_uchar *bit_area = (zend_uchar*) row_buffer->ptr + data_size + 1; /* we allocate from here */
-       zend_bool as_unicode = conn->options.numeric_and_datetime_as_unicode;
-#ifdef MYSQLND_STRING_TO_INT_CONVERSION
-       zend_bool as_int_or_float = conn->options.int_and_float_native;
-#endif
 
        DBG_ENTER("php_mysqlnd_rowp_read_text_protocol");
 
@@ -1492,12 +1725,12 @@ void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
                unsigned long len = php_mysqlnd_net_field_length(&p);
 
 #ifdef USE_ZVAL_CACHE
-               obj = mysqlnd_palloc_get_zval(conn->zval_cache, &allocated TSRMLS_CC);
+               obj = mysqlnd_palloc_get_zval(zval_cache, &allocated TSRMLS_CC);
                if (allocated) {
                        *current_field = (zval *) obj;
                } else {
                        /* It's from the cache, so we can upcast here */
-                       *current_field = &((mysqlnd_zval *) obj)->zv;   
+                       *current_field = &((mysqlnd_zval *) obj)->zv;
                        ((mysqlnd_zval *) obj)->point_type = MYSQLND_POINTS_FREE;
                }
 #else
@@ -1507,7 +1740,7 @@ void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
 
                if (current_field > start_field && last_field_was_string) {
                        /*
-                         Normal queries: 
+                         Normal queries:
                          We have to put \0 now to the end of the previous field, if it was
                          a string. IS_NULL doesn't matter. Because we have already read our
                          length, then we can overwrite it in the row buffer.
@@ -1561,8 +1794,8 @@ void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
                                        case MYSQL_TYPE_STRING:         statistic = STAT_TEXT_TYPE_FETCHED_STRING; break;
                                        case MYSQL_TYPE_GEOMETRY:       statistic = STAT_TEXT_TYPE_FETCHED_GEOMETRY; break;
                                        default: statistic = STAT_TEXT_TYPE_FETCHED_OTHER; break;
-                               }                       
-                               MYSQLND_INC_CONN_STATISTIC(&conn->stats, statistic);
+                               }
+                               MYSQLND_INC_CONN_STATISTIC(stats, statistic);
                        }
 
 #ifdef MYSQLND_STRING_TO_INT_CONVERSION
@@ -1594,7 +1827,7 @@ void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
 #if SIZEOF_LONG==8
                                        if (uns == TRUE && v > 9223372036854775807L)
 #elif SIZEOF_LONG==4
-                                       if ((uns == TRUE && v > L64(2147483647)) || 
+                                       if ((uns == TRUE && v > L64(2147483647)) ||
                                                (uns == FALSE && (( L64(2147483647) < (int64_t) v) ||
                                                (L64(-2147483648) > (int64_t) v))))
 #endif /* SIZEOF */
@@ -1636,7 +1869,7 @@ void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
 #if PHP_MAJOR_VERSION >= 6
                                        if (as_unicode) {
                                                ZVAL_UTF8_STRINGL(*current_field, start, bit_area - start - 1, 0);
-                                       } else                  
+                                       } else
 #endif
                                        {
                                                ZVAL_STRINGL(*current_field, (char *) start, bit_area - start - 1, 0);
@@ -1652,7 +1885,7 @@ void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
 #if PHP_MAJOR_VERSION >= 6
                                        if (as_unicode) {
                                                ZVAL_UTF8_STRINGL(*current_field, start, bit_area - start - 1, 0);
-                                       } else                  
+                                       } else
 #endif
                                        {
                                                ZVAL_STRINGL(*current_field, (char *) start, bit_area - start - 1, 0);
@@ -1665,7 +1898,7 @@ void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
                                  IS_UNICODE should not be specially handled. In unicode mode
                                  the buffers are not referenced - everything is copied.
                                */
-                       } else 
+                       } else
 #if PHP_MAJOR_VERSION < 6
                        {
                                ZVAL_STRINGL(*current_field, (char *)p, len, 0);
@@ -1730,7 +1963,7 @@ void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer,
 
 /* {{{ php_mysqlnd_rowp_read */
 /*
-  if normal statements => packet->fields is created by this function, 
+  if normal statements => packet->fields is created by this function,
   if PS => packet->fields is passed from outside
 */
 static enum_func_status
@@ -1752,7 +1985,7 @@ php_mysqlnd_rowp_read(void *_packet, MYSQLND *conn TSRMLS_DC)
                        packet->bit_fields_total_len + packet->bit_fields_count;
        }
 
-       ret = php_mysqlnd_read_row_ex(conn, &packet->row_buffer, &data_size,
+       ret = php_mysqlnd_read_row_ex(conn, packet->result_set_memory_pool, &packet->row_buffer, &data_size,
                                                                  packet->persistent_alloc, post_alloc_for_bit_fields
                                                                  TSRMLS_CC);
        if (FAIL == ret) {
@@ -1862,12 +2095,13 @@ void php_mysqlnd_rowp_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
 static enum_func_status
 php_mysqlnd_stats_read(void *_packet, MYSQLND *conn TSRMLS_DC)
 {
-       zend_uchar buf[1024];
        php_mysql_packet_stats *packet= (php_mysql_packet_stats *) _packet;
+       size_t buf_len = conn->net.cmd_buffer.length;
+       zend_uchar *buf = (zend_uchar *) conn->net.cmd_buffer.buffer;
 
        DBG_ENTER("php_mysqlnd_stats_read");
 
-       PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "statistics", PROT_STATS_PACKET);
+       PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "statistics", PROT_STATS_PACKET);
 
        packet->message = mnd_emalloc(packet->header.size + 1);
        memcpy(packet->message, buf, packet->header.size);
@@ -1904,7 +2138,8 @@ static enum_func_status
 php_mysqlnd_prepare_read(void *_packet, MYSQLND *conn TSRMLS_DC)
 {
        /* In case of an error, we should have place to put it */
-       zend_uchar buf[1024];
+       size_t buf_len = conn->net.cmd_buffer.length;
+       zend_uchar *buf = (zend_uchar *) conn->net.cmd_buffer.buffer;
        zend_uchar *p = buf;
        zend_uchar *begin = buf;
        unsigned int data_size;
@@ -1912,8 +2147,8 @@ php_mysqlnd_prepare_read(void *_packet, MYSQLND *conn TSRMLS_DC)
 
        DBG_ENTER("php_mysqlnd_prepare_read");
 
-       PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "prepare", PROT_PREPARE_RESP_PACKET);
-       
+       PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "prepare", PROT_PREPARE_RESP_PACKET);
+
        data_size = packet->header.size;
        packet->error_code = uint1korr(p);
        p++;
@@ -1984,14 +2219,15 @@ static enum_func_status
 php_mysqlnd_chg_user_read(void *_packet, MYSQLND *conn TSRMLS_DC)
 {
        /* There could be an error message */
-       zend_uchar buf[1024];
+       size_t buf_len = conn->net.cmd_buffer.length;
+       zend_uchar *buf = (zend_uchar *) conn->net.cmd_buffer.buffer;
        zend_uchar *p = buf;
        zend_uchar *begin = buf;
        php_mysql_packet_chg_user_resp *packet= (php_mysql_packet_chg_user_resp *) _packet;
 
        DBG_ENTER("php_mysqlnd_chg_user_read");
 
-       PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "change user response", PROT_CHG_USER_PACKET);
+       PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "change user response", PROT_CHG_USER_PACKET);
 
        /*
          Don't increment. First byte is 0xFF on error, but otherwise is starting byte
@@ -2038,7 +2274,7 @@ void php_mysqlnd_chg_user_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
 /* }}} */
 
 
-/* {{{ packet_methods 
+/* {{{ packet_methods
  */
 mysqlnd_packet_methods packet_methods[PROT_LAST] =
 {
index 77ee795c35a1be7449c1fa5ab30adce6e870dea5..ae05cb68db791c571574a6258507152c64c9f544 100644 (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 */
 
index 1465681bd303d40cf008a0308117bcc4d6230cc8..585e5d86a7a33a6d5d4325d279d8fa1931d9730c 100644 (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),