diff options
author | Andrey Hristov <andrey@php.net> | 2009-08-28 09:30:16 +0000 |
---|---|---|
committer | Andrey Hristov <andrey@php.net> | 2009-08-28 09:30:16 +0000 |
commit | e8412fb61c53e69bf098986f28a03c40f4d50f44 (patch) | |
tree | bd5f7a7b28d589be65fafbe326d3e7d6064330a6 | |
parent | 5c7b1336488dcd331deb6cd3edea73a42bd4caa9 (diff) | |
download | php-git-e8412fb61c53e69bf098986f28a03c40f4d50f44.tar.gz |
Fix for bug#48745
mysqlnd: mysql_num_fields returns wrong column count for mysql_list_fields
-rw-r--r-- | ext/mysqlnd/mysqlnd.h | 8 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_block_alloc.c | 21 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_block_alloc.h | 3 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_debug.c | 3 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_enum_n_def.h | 9 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_palloc.c | 37 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_ps.c | 10 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_result.c | 87 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_result_meta.c | 1 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_structs.h | 6 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_wireprotocol.c | 36 | ||||
-rw-r--r-- | ext/mysqlnd/php_mysqlnd.c | 4 |
12 files changed, 74 insertions, 151 deletions
diff --git a/ext/mysqlnd/mysqlnd.h b/ext/mysqlnd/mysqlnd.h index ba3afed3e0..687b989303 100644 --- a/ext/mysqlnd/mysqlnd.h +++ b/ext/mysqlnd/mysqlnd.h @@ -17,19 +17,17 @@ | Ulf Wendel <uwendel@mysql.com> | +----------------------------------------------------------------------+ */ - /* $Id$ */ #ifndef MYSQLND_H #define MYSQLND_H -#define MYSQLND_VERSION "mysqlnd/PHP " PHP_VERSION " $Revision$" -#define MYSQLND_VERSION_ID PHP_VERSION_ID +#define MYSQLND_VERSION "mysqlnd 5.0.5-dev - 081106 - $Revision$" +#define MYSQLND_VERSION_ID 50005 /* This forces inlining of some accessor functions */ #define MYSQLND_USE_OPTIMISATIONS 1 - #define MYSQLND_STRING_TO_INT_CONVERSION /* This force mysqlnd to do a single (or more depending on ammount of data) @@ -318,9 +316,11 @@ PHPAPI MYSQLND_THD_ZVAL_PCACHE * _mysqlnd_palloc_rinit(MYSQLND_ZVAL_PCACHE * cac PHPAPI void _mysqlnd_palloc_rshutdown(MYSQLND_THD_ZVAL_PCACHE * cache TSRMLS_DC); +#define mysqlnd_palloc_init_thd_cache(cache) _mysqlnd_palloc_init_thd_cache((cache) TSRMLS_CC) #define mysqlnd_palloc_free_thd_cache_reference(cache) _mysqlnd_palloc_free_thd_cache_reference((cache) TSRMLS_CC) #define mysqlnd_palloc_get_thd_cache_reference(cache) _mysqlnd_palloc_get_thd_cache_reference((cache) TSRMLS_CC) +PHPAPI MYSQLND_THD_ZVAL_PCACHE* _mysqlnd_palloc_init_thd_cache(MYSQLND_ZVAL_PCACHE * const cache TSRMLS_DC); MYSQLND_THD_ZVAL_PCACHE* _mysqlnd_palloc_get_thd_cache_reference(MYSQLND_THD_ZVAL_PCACHE * const cache TSRMLS_DC); PHPAPI void _mysqlnd_palloc_free_thd_cache_reference(MYSQLND_THD_ZVAL_PCACHE **cache TSRMLS_DC); diff --git a/ext/mysqlnd/mysqlnd_block_alloc.c b/ext/mysqlnd/mysqlnd_block_alloc.c index a9e2896049..2dcedcbfe6 100644 --- a/ext/mysqlnd/mysqlnd_block_alloc.c +++ b/ext/mysqlnd/mysqlnd_block_alloc.c @@ -35,7 +35,7 @@ mysqlnd_mempool_free_contents(MYSQLND_MEMORY_POOL * pool TSRMLS_DC) DBG_ENTER("mysqlnd_mempool_dtor"); for (i = 0; i < pool->free_chunk_list_elements; i++) { MYSQLND_MEMORY_POOL_CHUNK * chunk = pool->free_chunk_list[i]; - mysqlnd_mempool_free_chunk(chunk, FALSE TSRMLS_CC); + chunk->free_chunk(chunk, FALSE TSRMLS_CC); } DBG_VOID_RETURN; @@ -44,14 +44,11 @@ mysqlnd_mempool_free_contents(MYSQLND_MEMORY_POOL * pool TSRMLS_DC) /* {{{ mysqlnd_mempool_free_chunk */ -void +static void mysqlnd_mempool_free_chunk(MYSQLND_MEMORY_POOL_CHUNK * chunk, zend_bool cache_it TSRMLS_DC) { MYSQLND_MEMORY_POOL * pool = chunk->pool; DBG_ENTER("mysqlnd_mempool_free_chunk"); - if (!chunk) { - DBG_VOID_RETURN; - } if (chunk->from_pool) { /* Try to back-off and guess if this is the last block allocated */ if (chunk->ptr == (pool->arena + (pool->arena_size - pool->free_size - chunk->size))) { @@ -78,7 +75,7 @@ mysqlnd_mempool_free_chunk(MYSQLND_MEMORY_POOL_CHUNK * chunk, zend_bool cache_it /* {{{ mysqlnd_mempool_resize_chunk */ -void +static void mysqlnd_mempool_resize_chunk(MYSQLND_MEMORY_POOL_CHUNK * chunk, unsigned int size TSRMLS_DC) { DBG_ENTER("mysqlnd_mempool_resize_chunk"); @@ -138,6 +135,8 @@ MYSQLND_MEMORY_POOL_CHUNK * mysqlnd_mempool_get_chunk(MYSQLND_MEMORY_POOL * pool chunk = mnd_malloc(sizeof(MYSQLND_MEMORY_POOL_CHUNK)); } + chunk->free_chunk = mysqlnd_mempool_free_chunk; + chunk->resize_chunk = mysqlnd_mempool_resize_chunk; chunk->size = size; /* Should not go over MYSQLND_MAX_PACKET_SIZE, since we @@ -184,12 +183,10 @@ void mysqlnd_mempool_destroy(MYSQLND_MEMORY_POOL * pool TSRMLS_DC) { DBG_ENTER("mysqlnd_mempool_destroy"); - if (pool) { - /* mnd_free will reference LOCK_access and might crash, depending on the caller...*/ - mysqlnd_mempool_free_contents(pool TSRMLS_CC); - mnd_free(pool->arena); - mnd_free(pool); - } + /* mnd_free will reference LOCK_access and might crash, depending on the caller...*/ + mysqlnd_mempool_free_contents(pool TSRMLS_CC); + mnd_free(pool->arena); + mnd_free(pool); DBG_VOID_RETURN; } /* }}} */ diff --git a/ext/mysqlnd/mysqlnd_block_alloc.h b/ext/mysqlnd/mysqlnd_block_alloc.h index feace67451..505a23b2ee 100644 --- a/ext/mysqlnd/mysqlnd_block_alloc.h +++ b/ext/mysqlnd/mysqlnd_block_alloc.h @@ -25,9 +25,6 @@ MYSQLND_MEMORY_POOL * mysqlnd_mempool_create(size_t arena_size TSRMLS_DC); void mysqlnd_mempool_destroy(MYSQLND_MEMORY_POOL * pool TSRMLS_DC); -void mysqlnd_mempool_resize_chunk(MYSQLND_MEMORY_POOL_CHUNK * chunk, unsigned int size TSRMLS_DC); -void mysqlnd_mempool_free_chunk(MYSQLND_MEMORY_POOL_CHUNK * chunk, zend_bool cache_it TSRMLS_DC); - #endif /* MYSQLND_BLOCK_ALLOC_H */ diff --git a/ext/mysqlnd/mysqlnd_debug.c b/ext/mysqlnd/mysqlnd_debug.c index 2b5724dbe9..a052748850 100644 --- a/ext/mysqlnd/mysqlnd_debug.c +++ b/ext/mysqlnd/mysqlnd_debug.c @@ -830,9 +830,6 @@ void * _mysqlnd_perealloc(void *ptr, size_t new_size, zend_bool persistent MYSQL void _mysqlnd_efree(void *ptr MYSQLND_MEM_D) { DBG_ENTER(mysqlnd_efree_name); - if (!ptr) { - DBG_VOID_RETURN; - } #ifdef MYSQLND_THREADED if (MYSQLND_G(thread_id) != tsrm_thread_id()) { DBG_RETURN(_mysqlnd_pefree(ptr, 1 TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)); diff --git a/ext/mysqlnd/mysqlnd_enum_n_def.h b/ext/mysqlnd/mysqlnd_enum_n_def.h index 63762c508d..fec2261775 100644 --- a/ext/mysqlnd/mysqlnd_enum_n_def.h +++ b/ext/mysqlnd/mysqlnd_enum_n_def.h @@ -142,6 +142,7 @@ typedef enum mysqlnd_option MYSQLND_OPT_NET_READ_BUFFER_SIZE = 203, } enum_mysqlnd_option; + typedef enum mysqlnd_field_types { MYSQL_TYPE_DECIMAL, @@ -176,6 +177,7 @@ typedef enum mysqlnd_field_types /* Please update this if there is a new type after MYSQL_TYPE_GEOMETRY */ #define MYSQL_TYPE_LAST MYSQL_TYPE_GEOMETRY + typedef enum mysqlnd_server_option { MYSQL_OPTION_MULTI_STATEMENTS_ON, @@ -239,6 +241,7 @@ typedef enum mysqlnd_server_option /* see mysqlnd_charset.c for more information */ #define MYSQLND_BINARY_CHARSET_NR 63 + /* /-----> CONN_CLOSE <---------------\ | ^ \ @@ -258,6 +261,7 @@ typedef enum mysqlnd_connection_state CONN_QUIT_SENT, /* object is "destroyed" at this stage */ } enum_mysqlnd_connection_state; + typedef enum mysqlnd_stmt_state { MYSQLND_STMT_INITTED = 0, @@ -268,11 +272,13 @@ typedef enum mysqlnd_stmt_state MYSQLND_STMT_USER_FETCHING, /* fetch_row_buff or fetch_row_unbuf */ } enum_mysqlnd_stmt_state; + typedef enum param_bind_flags { MYSQLND_PARAM_BIND_BLOB_USED = 1 } enum_param_bind_flags; + /* PS */ enum mysqlnd_stmt_attr { @@ -280,6 +286,7 @@ enum mysqlnd_stmt_attr STMT_ATTR_CURSOR_TYPE, STMT_ATTR_PREFETCH_ROWS }; + enum myslqnd_cursor_type { CURSOR_TYPE_NO_CURSOR= 0, @@ -287,6 +294,7 @@ enum myslqnd_cursor_type CURSOR_TYPE_FOR_UPDATE= 2, CURSOR_TYPE_SCROLLABLE= 4 }; + typedef enum mysqlnd_connection_close_type { MYSQLND_CLOSE_EXPLICIT = 0, @@ -295,6 +303,7 @@ typedef enum mysqlnd_connection_close_type MYSQLND_CLOSE_LAST /* for checking, should always be last */ } enum_connection_close_type; + typedef enum mysqlnd_collected_stats { STAT_BYTES_SENT, diff --git a/ext/mysqlnd/mysqlnd_palloc.c b/ext/mysqlnd/mysqlnd_palloc.c index 4691639f91..1b035ed365 100644 --- a/ext/mysqlnd/mysqlnd_palloc.c +++ b/ext/mysqlnd/mysqlnd_palloc.c @@ -82,7 +82,6 @@ PHPAPI MYSQLND_ZVAL_PCACHE* _mysqlnd_palloc_init_cache(unsigned int cache_size T /* {{{ mysqlnd_palloc_get_cache_reference */ -static inline MYSQLND_ZVAL_PCACHE* mysqlnd_palloc_get_cache_reference(MYSQLND_ZVAL_PCACHE * const cache) { if (cache) { @@ -95,20 +94,6 @@ MYSQLND_ZVAL_PCACHE* mysqlnd_palloc_get_cache_reference(MYSQLND_ZVAL_PCACHE * co /* }}} */ -/* {{{ mysqlnd_palloc_release_cache_reference */ -static inline -MYSQLND_ZVAL_PCACHE* mysqlnd_palloc_release_cache_reference(MYSQLND_ZVAL_PCACHE * const cache) -{ - if (cache) { - LOCK_PCACHE(cache); - cache->references--; - UNLOCK_PCACHE(cache); - } - return cache; -} -/* }}} */ - - /* {{{ mysqlnd_palloc_free_cache */ /* As this call will happen on MSHUTDOWN(), then we don't need to copy the zvals with @@ -137,9 +122,9 @@ void _mysqlnd_palloc_free_cache(MYSQLND_ZVAL_PCACHE *cache TSRMLS_DC) /* {{{ _mysqlnd_palloc_init_thd_cache */ -MYSQLND_THD_ZVAL_PCACHE* mysqlnd_palloc_init_thd_cache(MYSQLND_ZVAL_PCACHE * const cache TSRMLS_DC) +PHPAPI MYSQLND_THD_ZVAL_PCACHE* _mysqlnd_palloc_init_thd_cache(MYSQLND_ZVAL_PCACHE * const cache TSRMLS_DC) { - MYSQLND_THD_ZVAL_PCACHE *ret = mnd_ecalloc(1, sizeof(MYSQLND_THD_ZVAL_PCACHE)); + MYSQLND_THD_ZVAL_PCACHE *ret = calloc(1, sizeof(MYSQLND_THD_ZVAL_PCACHE)); DBG_ENTER("_mysqlnd_palloc_init_thd_cache"); DBG_INF_FMT("ret = %p", ret); @@ -161,7 +146,7 @@ MYSQLND_THD_ZVAL_PCACHE* mysqlnd_palloc_init_thd_cache(MYSQLND_ZVAL_PCACHE * con ret->references = 1; /* 1. Initialize the GC list */ - ret->gc_list.ptr_line = mnd_ecalloc(cache->max_items, sizeof(mysqlnd_zval *)); + ret->gc_list.ptr_line = calloc(cache->max_items, sizeof(mysqlnd_zval *)); /* Backward and forward looping is possible */ ret->gc_list.last_added = ret->gc_list.ptr_line; ret->gc_list.canary1 = (void*)0xCAFE; @@ -178,18 +163,17 @@ MYSQLND_THD_ZVAL_PCACHE* _mysqlnd_palloc_get_thd_cache_reference(MYSQLND_THD_ZVA { DBG_ENTER("_mysqlnd_palloc_get_thd_cache_reference"); if (cache) { + ++cache->references; DBG_INF_FMT("cache=%p new_refc=%d gc_list.canary1=%p gc_list.canary2=%p", cache, cache->references, cache->gc_list.canary1, cache->gc_list.canary2); mysqlnd_palloc_get_cache_reference(cache->parent); - /* No concurrency here, we are in the same thread */ - ++cache->references; } DBG_RETURN(cache); } /* }}} */ -/* {{{ mysqlnd_palloc_free_thd_cache */ +/* {{{ mysqlnd_palloc_free_cache */ /* As this call will happen on MSHUTDOWN(), then we don't need to copy the zvals with copy_ctor but scrap what they point to with zval_dtor() and then just free our @@ -233,8 +217,8 @@ void mysqlnd_palloc_free_thd_cache(MYSQLND_THD_ZVAL_PCACHE *thd_cache TSRMLS_DC) UNLOCK_PCACHE(global_cache); } - mnd_efree(thd_cache->gc_list.ptr_line); - mnd_efree(thd_cache); + mnd_free(thd_cache->gc_list.ptr_line); + mnd_free(thd_cache); DBG_VOID_RETURN; } @@ -246,7 +230,7 @@ PHPAPI void _mysqlnd_palloc_free_thd_cache_reference(MYSQLND_THD_ZVAL_PCACHE **c { DBG_ENTER("_mysqlnd_palloc_free_thd_cache_reference"); if (*cache) { - mysqlnd_palloc_release_cache_reference((*cache)->parent); + --(*cache)->parent->references; DBG_INF_FMT("cache=%p references_left=%d canary1=%p canary2=%p", *cache, (*cache)->references, (*cache)->gc_list.canary1, (*cache)->gc_list.canary2); @@ -413,9 +397,6 @@ void mysqlnd_palloc_zval_ptr_dtor(zval **zv, MYSQLND_THD_ZVAL_PCACHE * const thd { MYSQLND_ZVAL_PCACHE *cache; DBG_ENTER("mysqlnd_palloc_zval_ptr_dtor"); - if (!*zv) { - DBG_VOID_RETURN; - } if (thd_cache) { DBG_INF_FMT("cache=%p parent_block=%p last_in_block=%p *zv=%p refc=%d type=%d ", thd_cache, @@ -547,7 +528,7 @@ void mysqlnd_palloc_zval_ptr_dtor(zval **zv, MYSQLND_THD_ZVAL_PCACHE * const thd /* {{{ _mysqlnd_palloc_rinit */ PHPAPI MYSQLND_THD_ZVAL_PCACHE * _mysqlnd_palloc_rinit(MYSQLND_ZVAL_PCACHE * cache TSRMLS_DC) { - return mysqlnd_palloc_init_thd_cache(cache TSRMLS_CC); + return mysqlnd_palloc_init_thd_cache(cache); } /* }}} */ diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 18eab05be7..ba4ea3120f 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -871,7 +871,7 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int result->meta->fields[i].max_length = Z_STRLEN_P(data); } stmt->result_bind[i].zv->value = data->value; - /* copied data, thus also the ownership. Thus null data */ + // copied data, thus also the ownership. Thus null data ZVAL_NULL(data); } } @@ -885,7 +885,7 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int the bound variables. Thus we need to do part of what it does or Zend will report leaks. */ - mysqlnd_mempool_free_chunk(row_packet->row_buffer, TRUE TSRMLS_CC); + row_packet->row_buffer->free_chunk(row_packet->row_buffer, TRUE TSRMLS_CC); row_packet->row_buffer = NULL; } } else if (ret == FAIL) { @@ -1047,7 +1047,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla result->meta->fields[i].max_length = Z_STRLEN_P(data); } stmt->result_bind[i].zv->value = data->value; - /* copied data, thus also the ownership. Thus null data */ + // copied data, thus also the ownership. Thus null data ZVAL_NULL(data); } } @@ -1060,13 +1060,13 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla the bound variables. Thus we need to do part of what it does or Zend will report leaks. */ - mysqlnd_mempool_free_chunk(row_packet->row_buffer, TRUE TSRMLS_CC); + row_packet->row_buffer->free_chunk(row_packet->row_buffer, TRUE TSRMLS_CC); row_packet->row_buffer = NULL; } /* We asked for one row, the next one should be EOF, eat it */ ret = PACKET_READ(row_packet, result->conn); if (row_packet->row_buffer) { - mysqlnd_mempool_free_chunk(row_packet->row_buffer, TRUE TSRMLS_CC); + row_packet->row_buffer->free_chunk(row_packet->row_buffer, TRUE TSRMLS_CC); row_packet->row_buffer = NULL; } MYSQLND_INC_CONN_STATISTIC(&stmt->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_PS_CURSOR); diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c index ded48930a5..56969944aa 100644 --- a/ext/mysqlnd/mysqlnd_result.c +++ b/ext/mysqlnd/mysqlnd_result.c @@ -30,9 +30,6 @@ #include "mysqlnd_debug.h" #include "ext/standard/basic_functions.h" -#define START_FREEING_AFTER_X_ROWS 10 -static void mysqlnd_buffered_free_previous_row(MYSQLND_RES *result, int which TSRMLS_DC); - #define MYSQLND_SILENT #ifdef MYSQLND_THREADED @@ -104,18 +101,11 @@ void mysqlnd_res_initialize_result_set_rest(MYSQLND_RES * const result TSRMLS_DC 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_INF_FMT("before heap=%lu real=%lu", zend_memory_usage(FALSE TSRMLS_CC), zend_memory_usage(TRUE TSRMLS_CC)); if (!data_cursor || row_count == result->stored_data->initialized_rows) { DBG_VOID_RETURN; } while ((data_cursor - data_begin) < (row_count * field_count)) { - if (START_FREEING_AFTER_X_ROWS < ((data_cursor - data_begin) / result->field_count)) { - zval **orig_data_cursor = result->stored_data->data_cursor; - result->stored_data->data_cursor = data_cursor; - mysqlnd_buffered_free_previous_row(result, START_FREEING_AFTER_X_ROWS TSRMLS_CC); - result->stored_data->data_cursor = orig_data_cursor; - } if (NULL == data_cursor[0]) { result->stored_data->initialized_rows++; result->m.row_decoder( @@ -140,7 +130,6 @@ void mysqlnd_res_initialize_result_set_rest(MYSQLND_RES * const result TSRMLS_DC } data_cursor += field_count; } - DBG_INF_FMT("after heap=%lu real=%lu", zend_memory_usage(FALSE TSRMLS_CC), zend_memory_usage(TRUE TSRMLS_CC)); DBG_VOID_RETURN; } /* }}} */ @@ -188,7 +177,7 @@ void mysqlnd_unbuffered_free_last_data(MYSQLND_RES *result TSRMLS_DC) if (unbuf->last_row_buffer) { DBG_INF("Freeing last row buffer"); /* Nothing points to this buffer now, free it */ - mysqlnd_mempool_free_chunk(unbuf->last_row_buffer, TRUE TSRMLS_CC); + unbuf->last_row_buffer->free_chunk(unbuf->last_row_buffer, TRUE TSRMLS_CC); unbuf->last_row_buffer = NULL; } @@ -197,53 +186,6 @@ void mysqlnd_unbuffered_free_last_data(MYSQLND_RES *result TSRMLS_DC) /* }}} */ -/* {{{ mysqlnd_buffered_free_previous_row */ -static -void mysqlnd_buffered_free_previous_row(MYSQLND_RES *result, int which TSRMLS_DC) -{ - MYSQLND_RES_BUFFERED * set = result->stored_data; - - DBG_ENTER("mysqlnd_buffered_free_previous_row"); - - if (!set) { - DBG_VOID_RETURN; - } - - DBG_INF_FMT("which=%d result->field_count=%d data=%p data_cursor=%p", which, result->field_count, set->data, set->data_cursor); - if (set->data_cursor && ((set->data_cursor - (which * result->field_count) ) >= set->data)) { - unsigned int i, ctor_called_count = 0; - zend_bool copy_ctor_called; - MYSQLND_STATS *global_stats = result->conn? &result->conn->stats:NULL; - zval **current_row = set->data_cursor - (which * result->field_count); - - DBG_INF_FMT("%u columns to free", result->field_count); - for (i = 0; i < result->field_count; i++) { - if (current_row[i]) { - mysqlnd_palloc_zval_ptr_dtor(&(current_row[i]), - result->zval_cache, result->type, - ©_ctor_called TSRMLS_CC); - if (copy_ctor_called) { - ctor_called_count++; - } - current_row[i] = NULL; - } - } - DBG_INF_FMT("copy_ctor_called_count=%u", ctor_called_count); - /* By using value3 macros we hold a mutex only once, there is no value2 */ - MYSQLND_INC_CONN_STATISTIC_W_VALUE3(global_stats, - STAT_COPY_ON_WRITE_PERFORMED, - ctor_called_count, - STAT_COPY_ON_WRITE_SAVED, - result->field_count - ctor_called_count, - STAT_COPY_ON_WRITE_PERFORMED, 0); - } - - DBG_VOID_RETURN; -} -/* }}} */ - - - /* {{{ mysqlnd_free_buffered_data */ void mysqlnd_free_buffered_data(MYSQLND_RES *result TSRMLS_DC) { @@ -263,20 +205,21 @@ void mysqlnd_free_buffered_data(MYSQLND_RES *result TSRMLS_DC) for (col = field_count - 1; col >= 0; --col) { zend_bool copy_ctor_called; - if (current_row[col] != NULL) { - mysqlnd_palloc_zval_ptr_dtor(&(current_row[col]), zval_cache, + if (current_row[0] == NULL) { + break;/* row that was never initialized */ + } + mysqlnd_palloc_zval_ptr_dtor(&(current_row[col]), zval_cache, result->type, ©_ctor_called TSRMLS_CC); #if MYSQLND_DEBUG_MEMORY - DBG_INF_FMT("Copy_ctor_called=%d", copy_ctor_called); + DBG_INF_FMT("Copy_ctor_called=%d", copy_ctor_called); #endif - MYSQLND_INC_GLOBAL_STATISTIC(copy_ctor_called? STAT_COPY_ON_WRITE_PERFORMED: - STAT_COPY_ON_WRITE_SAVED); - } + MYSQLND_INC_GLOBAL_STATISTIC(copy_ctor_called? STAT_COPY_ON_WRITE_PERFORMED: + STAT_COPY_ON_WRITE_SAVED); } #if MYSQLND_DEBUG_MEMORY DBG_INF("Freeing current_row & current_buffer"); #endif - mysqlnd_mempool_free_chunk(current_buffer, TRUE TSRMLS_CC); + current_buffer->free_chunk(current_buffer, TRUE TSRMLS_CC); } DBG_INF("Freeing data & row_buffer"); if (set->data) { @@ -354,7 +297,7 @@ void mysqlnd_free_background_buffered_data(MYSQLND_RES *result TSRMLS_DC) #endif pefree(current_row, set->persistent); } - mysqlnd_mempool_free_chunk(current_buffer, TRUE TSRMLS_CC); + current_buffer->free_chunk(current_buffer, TRUE TSRMLS_CC); } DBG_INF("Freeing data & row_buffer"); pefree(set->data, set->persistent); @@ -488,6 +431,8 @@ MYSQLND_METHOD(mysqlnd_res, read_result_metadata)(MYSQLND_RES *result, MYSQLND * result->m.free_result_contents(result TSRMLS_CC); DBG_RETURN(FAIL); } + /* COM_FIELD_LIST is broken and has premature EOF, thus we need to hack here and in mysqlnd_res_meta.c */ + result->field_count = result->meta->field_count; /* 2. Follows an EOF packet, which the client of mysqlnd_read_result_metadata() @@ -1156,10 +1101,6 @@ mysqlnd_fetch_row_buffered(MYSQLND_RES *result, void *param, unsigned int flags, zval **current_row = set->data_cursor; MYSQLND_FIELD *field = result->meta->fields; struct mysqlnd_field_hash_key *zend_hash_key = result->meta->zend_hash_keys; - DBG_INF_FMT("row_num=%u", (set->data_cursor - set->data) / result->meta->field_count); - if (START_FREEING_AFTER_X_ROWS < ((set->data_cursor - set->data) / result->field_count)) { - mysqlnd_buffered_free_previous_row(result, START_FREEING_AFTER_X_ROWS TSRMLS_CC); - } if (NULL == current_row[0]) { uint64_t row_num = (set->data_cursor - set->data) / result->meta->field_count; @@ -1909,7 +1850,6 @@ MYSQLND_METHOD(mysqlnd_res, fetch_into)(MYSQLND_RES *result, unsigned int flags, DBG_ENTER("mysqlnd_res::fetch_into"); DBG_INF_FMT("flags=%u mysqlnd_extension=%d", flags, extension); - DBG_INF_FMT("memory in use: heap_size=%lu real_size=%u", zend_memory_usage(FALSE TSRMLS_CC), zend_memory_usage(TRUE TSRMLS_CC)); if (!result->m.fetch_row) { RETVAL_NULL(); @@ -1921,7 +1861,7 @@ MYSQLND_METHOD(mysqlnd_res, fetch_into)(MYSQLND_RES *result, unsigned int flags, */ mysqlnd_array_init(return_value, mysqlnd_num_fields(result) * 2); if (FAIL == result->m.fetch_row(result, (void *)return_value, flags, &fetched_anything TSRMLS_CC)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading/decoding a row"); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading a row"); RETVAL_FALSE; } else if (fetched_anything == FALSE) { zval_dtor(return_value); @@ -1939,7 +1879,6 @@ MYSQLND_METHOD(mysqlnd_res, fetch_into)(MYSQLND_RES *result, unsigned int flags, return_value is IS_NULL for no more data and an array for data. Thus it's ok to return here. */ - DBG_INF_FMT("returning: heap_size=%lu real_size=%u", zend_memory_usage(FALSE TSRMLS_CC), zend_memory_usage(TRUE TSRMLS_CC)); DBG_VOID_RETURN; } /* }}} */ diff --git a/ext/mysqlnd/mysqlnd_result_meta.c b/ext/mysqlnd/mysqlnd_result_meta.c index c970749ab6..7a75003927 100644 --- a/ext/mysqlnd/mysqlnd_result_meta.c +++ b/ext/mysqlnd/mysqlnd_result_meta.c @@ -166,6 +166,7 @@ MYSQLND_METHOD(mysqlnd_res_meta, read_metadata)(MYSQLND_RES_METADATA * const met DBG_RETURN(FAIL); } if (field_packet.stupid_list_fields_eof == TRUE) { + meta->field_count = i + 1; break; } diff --git a/ext/mysqlnd/mysqlnd_structs.h b/ext/mysqlnd/mysqlnd_structs.h index 2120e2d81f..ddb7b40da6 100644 --- a/ext/mysqlnd/mysqlnd_structs.h +++ b/ext/mysqlnd/mysqlnd_structs.h @@ -45,10 +45,12 @@ struct st_mysqlnd_memory_pool struct st_mysqlnd_memory_pool_chunk { - uint32_t app; + uint64_t app; MYSQLND_MEMORY_POOL *pool; zend_uchar *ptr; - uint32_t 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; }; diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c index 5a56a3b76a..989cc87ed0 100644 --- a/ext/mysqlnd/mysqlnd_wireprotocol.c +++ b/ext/mysqlnd/mysqlnd_wireprotocol.c @@ -43,6 +43,7 @@ #define MYSQLND_DUMP_HEADER_N_BODY2 #define MYSQLND_DUMP_HEADER_N_BODY_FULL2 + #define PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_size, packet_type_as_text, packet_type) \ { \ if (FAIL == mysqlnd_read_header((conn), &((packet)->header) TSRMLS_CC)) {\ @@ -70,6 +71,7 @@ 1); \ } + extern mysqlnd_packet_methods packet_methods[]; static const char *unknown_sqlstate= "HY000"; @@ -611,7 +613,7 @@ php_mysqlnd_greet_read(void *_packet, MYSQLND *conn TSRMLS_DC) /* pad2 */ p+= 13; - if ((size_t)(p - buf) < packet->header.size) { + if (p - buf < packet->header.size) { /* scramble_buf is split into two parts */ memcpy(packet->scramble_buf + SCRAMBLE_LENGTH_323, p, SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323); @@ -625,7 +627,7 @@ php_mysqlnd_greet_read(void *_packet, MYSQLND *conn TSRMLS_DC) DBG_INF_FMT("server_capabilities=%d charset_no=%d server_status=%d", packet->server_capabilities, packet->charset_no, packet->server_status); - if ((size_t)(p - begin) > packet->header.size) { + if (p - begin > packet->header.size) { DBG_ERR_FMT("GREET packet %d bytes shorter than expected", p - begin - packet->header.size); php_error_docref(NULL TSRMLS_CC, E_WARNING, "GREET packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected", p - begin - packet->header.size); @@ -810,7 +812,7 @@ php_mysqlnd_ok_read(void *_packet, MYSQLND *conn TSRMLS_DC) p+= 2; /* There is a message */ - if (packet->header.size > (size_t) (p - buf) && (i = php_mysqlnd_net_field_length(&p))) { + if (packet->header.size > p - buf && (i = php_mysqlnd_net_field_length(&p))) { packet->message = pestrndup((char *)p, MIN(i, sizeof(buf) - (p - buf)), conn->persistent); packet->message_len = i; } else { @@ -821,7 +823,7 @@ php_mysqlnd_ok_read(void *_packet, MYSQLND *conn TSRMLS_DC) packet->affected_rows, packet->last_insert_id, packet->server_status, packet->warning_count); - if ((size_t)(p - begin) > packet->header.size) { + if (p - begin > packet->header.size) { DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size); php_error_docref(NULL TSRMLS_CC, E_WARNING, "OK packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected", p - begin - packet->header.size); @@ -894,7 +896,7 @@ php_mysqlnd_eof_read(void *_packet, MYSQLND *conn TSRMLS_DC) packet->server_status = 0; } - if ((size_t)(p - begin) > packet->header.size) { + if (p - begin > packet->header.size) { DBG_ERR_FMT("EOF packet %d bytes shorter than expected", p - begin - packet->header.size); php_error_docref(NULL TSRMLS_CC, E_WARNING, "EOF packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected", p - begin - packet->header.size); @@ -1044,7 +1046,7 @@ php_mysqlnd_rset_header_read(void *_packet, MYSQLND *conn TSRMLS_DC) packet->warning_count = uint2korr(p); p+=2; /* Check for additional textual data */ - if (packet->header.size > (size_t) (p - buf) && (len = php_mysqlnd_net_field_length(&p))) { + if (packet->header.size > (p - buf) && (len = php_mysqlnd_net_field_length(&p))) { packet->info_or_local_file = mnd_pemalloc(len + 1, conn->persistent); memcpy(packet->info_or_local_file, p, len); packet->info_or_local_file[len] = '\0'; @@ -1059,7 +1061,7 @@ php_mysqlnd_rset_header_read(void *_packet, MYSQLND *conn TSRMLS_DC) /* Result set */ break; } - if ((size_t)(p - begin) > packet->header.size) { + if (p - begin > packet->header.size) { DBG_ERR_FMT("RSET_HEADER packet %d bytes shorter than expected", p - begin - packet->header.size); php_error_docref(NULL TSRMLS_CC, E_WARNING, "GREET packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected", p - begin - packet->header.size); @@ -1187,7 +1189,7 @@ php_mysqlnd_rset_field_read(void *_packet, MYSQLND *conn TSRMLS_DC) NULL_LENGTH (0xFB) comes from COM_FIELD_LIST when the default value is NULL. Otherwise the string is length encoded. */ - if (packet->header.size > (size_t)(p - buf) && + if (packet->header.size > (p - buf) && (len = php_mysqlnd_net_field_length(&p)) && len != MYSQLND_NULL_LENGTH) { @@ -1199,7 +1201,7 @@ php_mysqlnd_rset_field_read(void *_packet, MYSQLND *conn TSRMLS_DC) p += len; } - if ((size_t)(p - begin) > packet->header.size) { + if (p - begin > packet->header.size) { DBG_ERR_FMT("RSET field packet %d bytes shorter than expected", p - begin - packet->header.size); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Result set field packet "MYSQLND_SZ_T_SPEC" bytes " "shorter than expected", p - begin - packet->header.size); @@ -1327,7 +1329,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. */ - mysqlnd_mempool_resize_chunk((*buffer), *data_size + 1 TSRMLS_CC); + (*buffer)->resize_chunk((*buffer), *data_size + 1 TSRMLS_CC); /* The position could have changed, recalculate */ p = (*buffer)->ptr + (*data_size - header.size); } @@ -1343,8 +1345,8 @@ php_mysqlnd_read_row_ex(MYSQLND *conn, MYSQLND_MEMORY_POOL_CHUNK **buffer, break; } } - if (ret == FAIL && (*buffer)) { - mysqlnd_mempool_free_chunk(*buffer, TRUE TSRMLS_CC); + if (ret == FAIL) { + (*buffer)->free_chunk((*buffer), TRUE TSRMLS_CC); *buffer = NULL; } *data_size -= prealloc_more_bytes; @@ -1362,10 +1364,8 @@ void php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffe 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 = NULL; -#endif + void *obj; DBG_ENTER("php_mysqlnd_rowp_read_binary_protocol"); @@ -1827,7 +1827,7 @@ void php_mysqlnd_rowp_free_mem(void *_packet, zend_bool alloca TSRMLS_DC) DBG_ENTER("php_mysqlnd_rowp_free_mem"); p = (php_mysql_packet_row *) _packet; if (p->row_buffer) { - mysqlnd_mempool_free_chunk(p->row_buffer, TRUE TSRMLS_CC); + p->row_buffer->free_chunk(p->row_buffer, TRUE TSRMLS_CC); p->row_buffer = NULL; } DBG_INF_FMT("alloca=%d persistent=%d", (int)alloca, (int)p->header.persistent); @@ -1945,7 +1945,7 @@ php_mysqlnd_prepare_read(void *_packet, MYSQLND *conn TSRMLS_DC) DBG_INF_FMT("Prepare packet read: stmt_id=%d fields=%d params=%d", packet->stmt_id, packet->field_count, packet->param_count); - if ((size_t) (p - begin) > packet->header.size) { + if (p - begin > packet->header.size) { DBG_ERR_FMT("PREPARE packet %d bytes shorter than expected", p - begin - packet->header.size); php_error_docref(NULL TSRMLS_CC, E_WARNING, "PREPARE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected", p - begin - packet->header.size); @@ -2005,7 +2005,7 @@ php_mysqlnd_chg_user_read(void *_packet, MYSQLND *conn TSRMLS_DC) packet->error_info.sqlstate TSRMLS_CC); } - if ((size_t)(p - begin) > packet->header.size) { + if (p - begin > packet->header.size) { DBG_ERR_FMT("CHANGE_USER packet %d bytes shorter than expected", p - begin - packet->header.size); php_error_docref(NULL TSRMLS_CC, E_WARNING, "CHANGE_USER packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected", p - begin - packet->header.size); diff --git a/ext/mysqlnd/php_mysqlnd.c b/ext/mysqlnd/php_mysqlnd.c index 196b96e884..7ebb748024 100644 --- a/ext/mysqlnd/php_mysqlnd.c +++ b/ext/mysqlnd/php_mysqlnd.c @@ -46,13 +46,13 @@ PHPAPI void mysqlnd_minfo_print_hash(zval *values) zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(values), &pos_values); while (zend_hash_get_current_data_ex(Z_ARRVAL_P(values), - (void **)&values_entry, &pos_values) == SUCCESS) { + (void **)&values_entry, &pos_values) == SUCCESS) { + TSRMLS_FETCH(); zstr string_key; uint string_key_len; ulong num_key; int s_len; char *s = NULL; - TSRMLS_FETCH(); zend_hash_get_current_key_ex(Z_ARRVAL_P(values), &string_key, &string_key_len, &num_key, 0, &pos_values); |