List:Commits« Previous MessageNext Message »
From:ahristov Date:May 9 2007 12:09pm
Subject:PHP mysqlnd svn commit: r364 - branches/qcache/mysqlnd
View as plain text  
Author: ahristov
Date: 2007-05-09 12:09:41 +0200 (Wed, 09 May 2007)
New Revision: 364

Modified:
   branches/qcache/mysqlnd/mysqlnd.c
   branches/qcache/mysqlnd/mysqlnd.h
   branches/qcache/mysqlnd/mysqlnd_charset.c
   branches/qcache/mysqlnd/mysqlnd_charset.h
   branches/qcache/mysqlnd/mysqlnd_palloc.c
   branches/qcache/mysqlnd/mysqlnd_ps.c
Log:
Merge from trunk


Modified: branches/qcache/mysqlnd/mysqlnd.c
===================================================================
--- branches/qcache/mysqlnd/mysqlnd.c	2007-05-09 09:30:56 UTC (rev 363)
+++ branches/qcache/mysqlnd/mysqlnd.c	2007-05-09 10:09:41 UTC (rev 364)
@@ -24,6 +24,7 @@
 #include "mysqlnd_wireprotocol.h"
 #include "mysqlnd_priv.h"
 #include "mysqlnd_statistics.h"
+#include "mysqlnd_charset.h"
 #include "ext/standard/basic_functions.h"
 
 #define MYSQLND_SILENT
@@ -120,26 +121,26 @@
 	}
 
 	if (unbuf->last_row_data) {
-		int i;
+		unsigned int i, ctor_called_count = 0;
 		zend_bool copy_ctor_called;
+		MYSQLND_STATS *global_stats = result->conn? &result->conn->stats:NULL;
 		for (i = 0; i < result->field_count; i++) {
-			if (result->type == MYSQLND_RES_PS) {
-				/* Do nothing, before assigning we will clean */
-				zval_ptr_dtor(&unbuf->last_row_data[i]);
-			} else {
-				mysqlnd_palloc_zval_ptr_dtor(&(unbuf->last_row_data[i]),
-											 result->zval_cache, FALSE,
-											 &copy_ctor_called TSRMLS_CC);
-				if (copy_ctor_called) {
-					MYSQLND_INC_CONN_STATISTIC(&result->conn->stats,
-											   STAT_COPY_ON_WRITE_PERFORMED);
-					/* Increase global stats */
-				} else {
-					MYSQLND_INC_CONN_STATISTIC(&result->conn->stats,
-											   STAT_COPY_ON_WRITE_SAVED);
-				}
+			mysqlnd_palloc_zval_ptr_dtor(&(unbuf->last_row_data[i]),
+										 result->zval_cache,
+										 result->type == MYSQLND_RES_PS,
+										 &copy_ctor_called TSRMLS_CC);
+			if (copy_ctor_called) {
+				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);
+		
 		/* Free last row's zvals */
 		efree(unbuf->last_row_data);
 		unbuf->last_row_data = NULL;
@@ -1616,13 +1617,102 @@
 
 #define STORE_RESULT_PREALLOCATED_SET 32
 
+static enum_func_status
+_mysqlnd_store_result_fetch_data(MYSQLND * const conn, MYSQLND_RES_BUFFERED *set,
+								 MYSQLND_RES_METADATA *meta TSRMLS_DC)
+{
+	enum_func_status ret;
+	php_mysql_packet_row row_packet;
+	unsigned int next_extend = STORE_RESULT_PREALLOCATED_SET, free_rows;
+
+	free_rows = next_extend;
+
+	PACKET_INIT_ALLOCA(row_packet, PROT_ROW_PACKET);
+	row_packet.field_count = meta->field_count;
+	row_packet.binary_protocol = FALSE;
+	row_packet.fields_metadata = meta->fields;
+	/* Let the row packet fill our buffer and skip additional malloc + memcpy */
+	while (FAIL != (ret = PACKET_READ_ALLOCA(row_packet, conn)) && !row_packet.eof)
{
+		int i;
+		zval **current_row;
+
+		if (!free_rows) {
+			unsigned long total_rows = free_rows = next_extend = next_extend * 5 / 3; /* extend
with 33% */
+			total_rows += set->row_count;
+			set->data = perealloc(set->data,
+										   total_rows * sizeof(zval **), set->persistent);
+
+			set->row_buffers = perealloc(set->row_buffers,
+												  total_rows * sizeof(zend_uchar *), set->persistent);
+		}
+		free_rows--;
+		current_row = set->data[set->row_count] = row_packet.fields;
+		set->row_buffers[set->row_count] = row_packet.row_buffer;
+		set->row_count++;
+
+		/* So row_packet's destructor function won't efree() it */
+		row_packet.fields = NULL;
+		row_packet.row_buffer = NULL;
+
+		for (i = 0; i < row_packet.field_count; i++) {
+			unsigned long len;
+			/*
+			  NULL fields are 0 length, 0 is not more than 0
+			  String of zero size, definitely can't be the next max_length.
+			  Thus for NULL and zero-length we are quite efficient.
+			*/
+			if (Z_TYPE_P(current_row[i]) != IS_NULL &&
+				(len = Z_STRLEN_P(current_row[i])) &&
+				meta->fields[i].max_length < len)
+			{
+				meta->fields[i].max_length = len;
+			}
+		}
+		/*
+		  No need to FREE_ALLOCA as we can reuse the
+		  'lengths' and 'fields' arrays. For lengths its absolutely safe.
+		  'fields' is reused because the ownership of the strings has been
+		  transfered above. 
+		*/
+	}
+	MYSQLND_INC_CONN_STATISTIC_W_VALUE(&conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT,
+									   set->row_count);
+
+	/* Finally clean */
+	if (row_packet.eof) { 
+		conn->upsert_status.warning_count = row_packet.warning_count;
+		conn->upsert_status.server_status = row_packet.server_status;
+	}
+	/* save some memory */
+	if (free_rows) {
+		set->data = perealloc(set->data,
+									   set->row_count * sizeof(zval **),
+									   set->persistent);
+		set->row_buffers = perealloc(set->row_buffers,
+											  set->row_count * sizeof(zend_uchar *),
+											  set->persistent);
+	}
+
+	if (conn->upsert_status.server_status & SERVER_MORE_RESULTS_EXISTS) {
+		conn->state = CONN_NEXT_RESULT_PENDING;
+	} else {
+		conn->state = CONN_READY;
+	}
+
+	if (ret == FAIL) {
+		set->error_info = row_packet.error_info;
+	}
+	PACKET_FREE_ALLOCA(row_packet);
+
+	return ret;
+}
+
+
 /* {{{ mysqlnd_store_result */
 static
 MYSQLND_RES *_mysqlnd_store_result(MYSQLND * const conn, zend_bool to_cache TSRMLS_DC)
 {
 	enum_func_status ret;
-	unsigned int next_extend = STORE_RESULT_PREALLOCATED_SET, free_rows;
-	php_mysql_packet_row row_packet;
 	MYSQLND_RES *result;
 
 	if (!conn->current_result) {
@@ -1656,8 +1746,8 @@
 	/* Create room for 'next_extend' rows */
 
 	result->data				= pecalloc(1, sizeof(MYSQLND_RES_BUFFERED), to_cache);
-	result->data->data			= pemalloc(next_extend * sizeof(zval **), to_cache);
-	result->data->row_buffers	= pemalloc(next_extend * sizeof(zend_uchar *),
to_cache);
+	result->data->data			= pemalloc(STORE_RESULT_PREALLOCATED_SET * sizeof(zval **),
to_cache);
+	result->data->row_buffers	= pemalloc(STORE_RESULT_PREALLOCATED_SET *
sizeof(zend_uchar *), to_cache);
 	result->data->references	= 1;
 	result->data->persistent	= to_cache;
 	if (to_cache) {
@@ -1667,7 +1757,20 @@
 		result->conn_hash_key_len = conn->hash_key_len;
 	}
 	
-
+	ret =  _mysqlnd_store_result_fetch_data(conn, result->data, result->meta
TSRMLS_CC);
+	if (PASS == ret) {
+		/* Position at the first row */
+		result->data->data_cursor = result->data->data;
+		/* libmysql's documentation says it should be so for SELECT statements */
+		conn->upsert_status.affected_rows = result->data->row_count;
+	} else {
+		conn->error_info = result->data->error_info;
+		mysqlnd_internal_free_result(result TSRMLS_CC);
+		result = NULL;
+	}
+	return result;
+	
+#if 0
 	free_rows = next_extend;
 
 	PACKET_INIT_ALLOCA(row_packet, PROT_ROW_PACKET);
@@ -1762,6 +1865,7 @@
 	PACKET_FREE_ALLOCA(row_packet);
 
 	return result;
+#endif
 }
 /* }}} */
 
@@ -1861,49 +1965,7 @@
 static
 ulong _mysqlnd_real_escape_quotes(const MYSQLND * const conn, char *newstr, const char
*escapestr, int escapestr_len)
 {
-	const char 	*newstr_s = newstr;
-	const char 	*newstr_e = newstr + 2 * escapestr_len;
-	const char 	*end = escapestr + escapestr_len;
-	zend_bool	escape_overflow = FALSE;
-
-	for (;escapestr < end; escapestr++) {
-		/* check unicode characters */
-		if (conn->charset->char_maxlen > 1 &&
conn->charset->mb_charlen(*escapestr) > 1) {
-			uint len = conn->charset->mb_valid(escapestr, end);
-
-			/* check possible overflow */
-			if ((newstr + len) > newstr_e) {
-				escape_overflow = TRUE;
-				break;
-			}
-			/* copy mb char without escaping it */
-			while (len--) {
-				*newstr++ = *escapestr++;
-			}
-			escapestr--;
-			continue;
-		}
-		if (*newstr == '\'') {
-			if (newstr + 2 > newstr_e) {
-				escape_overflow = TRUE;
-				break;
-			}
-			*newstr++ = '\'';
-			*newstr++ = '\'';
-		} else {
-			if (newstr + 1 > newstr_e) {
-				escape_overflow = TRUE;
-				break;
-			}
-			*newstr++= *escapestr;
-		}
-	}
-	*newstr = '\0';
-
-	if (escape_overflow) {
-		return (ulong)~0;
-	}
-	return (ulong)(newstr - newstr_s);
+	return mysqlnd_cset_escape_quotes(conn->charset, newstr, escapestr, escapestr_len);
 }
 /* }}} */
 
@@ -1912,76 +1974,7 @@
 static
 ulong _mysqlnd_real_escape_slashes(const MYSQLND * const conn, char *newstr, const char
*escapestr, int escapestr_len)
 {
-	const char 	*newstr_s = newstr;
-	const char 	*newstr_e = newstr + 2 * escapestr_len;
-	const char 	*end = escapestr + escapestr_len;
-	zend_bool	escape_overflow = FALSE;
-	
-	for (;escapestr < end; escapestr++) {
-		char	esc = '\0';
-
-		/* check unicode characters */
-		if (conn->charset->char_maxlen > 1 &&
conn->charset->mb_charlen(*escapestr) > 1) {
-			uint len = conn->charset->mb_valid(escapestr, end);
-
-			/* check possible overflow */
-			if ((newstr + len) > newstr_e) {
-				escape_overflow = TRUE;
-				break;
-			}
-			/* copy mb char without escaping it */
-			while (len--) {
-				*newstr++ = *escapestr++;
-			}
-			escapestr--;
-			continue;
-		}
-		if (conn->charset->char_maxlen > 1 &&
conn->charset->mb_charlen(*escapestr) > 1) {
-			esc = *escapestr;
-		} else {
-			switch (*escapestr) {
-				case 0:
-					esc = '0';
-					break;
-				case '\n':
-					esc = 'n';
-					break;
-				case '\r':
-					esc = 'r';
-					break;
-				case '\\':
-				case '\'':
-				case '"':
-					esc = *escapestr;
-					break;
-				case '\032':
-					esc = 'Z';
-					break;
-			}
-		}
-		if (esc) {
-			if (newstr + 2 > newstr_e) {
-				escape_overflow = TRUE;
-				break;
-			}
-			/* copy escaped character */
-			*newstr++ = '\\';
-			*newstr++ = esc;
-		} else {
-			if (newstr + 1 > newstr_e) {
-				escape_overflow = TRUE;
-				break;
-			}
-			/* copy non escaped character */
-			*newstr++ = *escapestr;
-		}
-	}
-	*newstr = '\0';
-
-	if (escape_overflow) {
-		return (ulong)~0;
-	}
-	return (ulong)(newstr - newstr_s);
+	return mysqlnd_cset_escape_slashes(conn->charset, newstr, escapestr, escapestr_len);
 }
 /* }}} */
 

Modified: branches/qcache/mysqlnd/mysqlnd.h
===================================================================
--- branches/qcache/mysqlnd/mysqlnd.h	2007-05-09 09:30:56 UTC (rev 363)
+++ branches/qcache/mysqlnd/mysqlnd.h	2007-05-09 10:09:41 UTC (rev 364)
@@ -742,6 +742,9 @@
 	/* qcache */
 	MYSQLND_QCACHE		*qcache;
 	unsigned int		references;
+
+	zend_bool			async_invalid;
+	mysqlnd_error_info	error_info;
 };
 
 

Modified: branches/qcache/mysqlnd/mysqlnd_charset.c
===================================================================
--- branches/qcache/mysqlnd/mysqlnd_charset.c	2007-05-09 09:30:56 UTC (rev 363)
+++ branches/qcache/mysqlnd/mysqlnd_charset.c	2007-05-09 10:09:41 UTC (rev 364)
@@ -465,3 +465,130 @@
 	return NULL;
 }
 /* }}} */
+
+
+/* {{{ mysqlnd_cset_escape_quotes */
+ulong mysqlnd_cset_escape_quotes(const MYSQLND_CHARSET * const charset, char *newstr,
const char *escapestr, int escapestr_len)
+{
+	const char 	*newstr_s = newstr;
+	const char 	*newstr_e = newstr + 2 * escapestr_len;
+	const char 	*end = escapestr + escapestr_len;
+	zend_bool	escape_overflow = FALSE;
+
+	for (;escapestr < end; escapestr++) {
+		/* check unicode characters */
+		if (charset->char_maxlen > 1 && charset->mb_charlen(*escapestr) >
1) {
+			uint len = charset->mb_valid(escapestr, end);
+
+			/* check possible overflow */
+			if ((newstr + len) > newstr_e) {
+				escape_overflow = TRUE;
+				break;
+			}
+			/* copy mb char without escaping it */
+			while (len--) {
+				*newstr++ = *escapestr++;
+			}
+			escapestr--;
+			continue;
+		}
+		if (*newstr == '\'') {
+			if (newstr + 2 > newstr_e) {
+				escape_overflow = TRUE;
+				break;
+			}
+			*newstr++ = '\'';
+			*newstr++ = '\'';
+		} else {
+			if (newstr + 1 > newstr_e) {
+				escape_overflow = TRUE;
+				break;
+			}
+			*newstr++= *escapestr;
+		}
+	}
+	*newstr = '\0';
+
+	if (escape_overflow) {
+		return (ulong)~0;
+	}
+	return (ulong)(newstr - newstr_s);
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_cset_escape_slashes */
+ulong mysqlnd_cset_escape_slashes(const MYSQLND_CHARSET * const cset, char *newstr, const
char *escapestr, int escapestr_len)
+{
+	const char 	*newstr_s = newstr;
+	const char 	*newstr_e = newstr + 2 * escapestr_len;
+	const char 	*end = escapestr + escapestr_len;
+	zend_bool	escape_overflow = FALSE;
+	
+	for (;escapestr < end; escapestr++) {
+		char	esc = '\0';
+
+		/* check unicode characters */
+		if (cset->char_maxlen > 1 && cset->mb_charlen(*escapestr) > 1) {
+			uint len = cset->mb_valid(escapestr, end);
+
+			/* check possible overflow */
+			if ((newstr + len) > newstr_e) {
+				escape_overflow = TRUE;
+				break;
+			}
+			/* copy mb char without escaping it */
+			while (len--) {
+				*newstr++ = *escapestr++;
+			}
+			escapestr--;
+			continue;
+		}
+		if (cset->char_maxlen > 1 && cset->mb_charlen(*escapestr) > 1) {
+			esc = *escapestr;
+		} else {
+			switch (*escapestr) {
+				case 0:
+					esc = '0';
+					break;
+				case '\n':
+					esc = 'n';
+					break;
+				case '\r':
+					esc = 'r';
+					break;
+				case '\\':
+				case '\'':
+				case '"':
+					esc = *escapestr;
+					break;
+				case '\032':
+					esc = 'Z';
+					break;
+			}
+		}
+		if (esc) {
+			if (newstr + 2 > newstr_e) {
+				escape_overflow = TRUE;
+				break;
+			}
+			/* copy escaped character */
+			*newstr++ = '\\';
+			*newstr++ = esc;
+		} else {
+			if (newstr + 1 > newstr_e) {
+				escape_overflow = TRUE;
+				break;
+			}
+			/* copy non escaped character */
+			*newstr++ = *escapestr;
+		}
+	}
+	*newstr = '\0';
+
+	if (escape_overflow) {
+		return (ulong)~0;
+	}
+	return (ulong)(newstr - newstr_s);
+}
+/* }}} */

Modified: branches/qcache/mysqlnd/mysqlnd_charset.h
===================================================================
--- branches/qcache/mysqlnd/mysqlnd_charset.h	2007-05-09 09:30:56 UTC (rev 363)
+++ branches/qcache/mysqlnd/mysqlnd_charset.h	2007-05-09 10:09:41 UTC (rev 364)
@@ -20,3 +20,5 @@
 #include "php.h"
 #include "php_globals.h"
 
+ulong mysqlnd_cset_escape_quotes(const MYSQLND_CHARSET * const charset, char *newstr,
const char *escapestr, int escapestr_len);
+ulong mysqlnd_cset_escape_slashes(const MYSQLND_CHARSET * const cset, char *newstr, const
char *escapestr, int escapestr_len);

Modified: branches/qcache/mysqlnd/mysqlnd_palloc.c
===================================================================
--- branches/qcache/mysqlnd/mysqlnd_palloc.c	2007-05-09 09:30:56 UTC (rev 363)
+++ branches/qcache/mysqlnd/mysqlnd_palloc.c	2007-05-09 10:09:41 UTC (rev 364)
@@ -291,7 +291,8 @@
 
 #ifndef MYSQLND_SILENT
 	php_printf("[mysqlnd_palloc_get_zval %p] *last_added=%p free_items=%d\n",
-				cache, cache? cache->free_list.last_added:NULL, cache->free_items);
+				thd_cache, thd_cache? thd_cache->parent->free_list.last_added:NULL,
+				thd_cache->parent->free_items);
 #endif
 
 	if (thd_cache) {
@@ -338,7 +339,11 @@
 {
 	MYSQLND_ZVAL_PCACHE *cache;
 #ifndef MYSQLND_SILENT
-	php_printf("[mysqlnd_palloc_zval_ptr_dtor %p] *zv=%p ps=%d refc=%d\n", cache, *zv, ps,
ZVAL_REFCOUNT(*zv));
+	php_printf("[mysqlnd_palloc_zval_ptr_dtor %p] parent_block=%p last_in_block=%p *zv=%p
ps=%d refc=%d\n",
+				thd_cache,
+				thd_cache->parent? thd_cache->parent->block:NULL,
+				thd_cache->parent? thd_cache->parent->last_in_block:NULL,
+				*zv, ps, ZVAL_REFCOUNT(*zv));
 #endif
 	*copy_ctor_called = FALSE;
 	/* Check whether cache is used and the zval is from the cache */
@@ -349,7 +354,9 @@
 		  Thus the refcount is -1 than of a zval from the cache,
 		  because the zvals from the cache are owned by it.
 		*/
-		if (ZVAL_REFCOUNT(*zv) > 1) {
+		if (ps == TRUE) {
+			ZVAL_REFCOUNT(*zv) = 1;		
+		} else if (ZVAL_REFCOUNT(*zv) > 1) {
 			if (ps == FALSE) {
 				/*
 				  Not a prepared statement, then we have to
@@ -465,7 +472,7 @@
 	MYSQLND_ZVAL_PCACHE *cache;
 	mysqlnd_zval **p;
 #ifndef MYSQLND_SILENT
-	php_printf("[mysqlnd_palloc_rshutdown %p]\n", cache);
+	php_printf("[mysqlnd_palloc_rshutdown %p]\n", thd_cache);
 #endif
 	if (!thd_cache || !(cache = thd_cache->parent)) {
 		return;

Modified: branches/qcache/mysqlnd/mysqlnd_ps.c
===================================================================
--- branches/qcache/mysqlnd/mysqlnd_ps.c	2007-05-09 09:30:56 UTC (rev 363)
+++ branches/qcache/mysqlnd/mysqlnd_ps.c	2007-05-09 10:09:41 UTC (rev 364)
@@ -92,7 +92,7 @@
 	result->type			= MYSQLND_RES_PS;
 	result->m.fetch_row		= mysqlnd_fetch_stmt_row_buffered;
 	result->m.fetch_lengths	= NULL;/* makes no sense */
-	result->zval_cache		= NULL;
+	result->zval_cache		= mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache);
 
 	/* Create room for 'next_extend' rows */
 
@@ -666,7 +666,7 @@
 	result->m.fetch_row		= stmt->cursor_exists? mysqlnd_fetch_stmt_row_cursor:
 													mysqlnd_stmt_fetch_row_unbuffered;
 	result->m.fetch_lengths	= NULL; /* makes no sense */
-	result->zval_cache		= NULL;
+	result->zval_cache		= mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache);
 
 	result->unbuf	= ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
 
@@ -1160,7 +1160,6 @@
 MYSQLND_RES * _mysqlnd_stmt_result_metadata(MYSQLND_STMT * const stmt)
 {
 	MYSQLND_RES *result;
-	MYSQLND_THD_ZVAL_PCACHE * cache;
 
 	if (!stmt->field_count || !stmt->conn || !stmt->result) {
 		return NULL;
@@ -1171,10 +1170,11 @@
 			find a better way to do it. In different functions I have put
 			fuses to check for result->m.fetch_row() being NULL. This should
 			be handled in a better way.
-	
+
+	  In the meantime we don't need a zval cache reference for this fake
+	  result set, so we don't get one.
 	*/
-	cache = mysqlnd_palloc_get_thd_cache_reference(stmt->conn->zval_cache);
-	result = mysqlnd_result_init(stmt->field_count, cache);
+	result = mysqlnd_result_init(stmt->field_count, NULL);
 	result->type = MYSQLND_RES_NORMAL;
 	result->m.fetch_row = result->m.fetch_row_normal_unbuffered;
 	result->unbuf = ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));

Thread
PHP mysqlnd svn commit: r364 - branches/qcache/mysqlndahristov9 May