Pantek Library
Hosting Provided By
CybrHost
High Speed Hosting

PHP mysqlnd svn commit: r773 - in trunk: mysqlnd tests/ext/mysqli

From: <ahristov(at)mysql.com>
Date: Tue Jul 17 2007 - 08:36:35 EDT


Author: ahristov
Date: 2007-07-17 14:36:34 +0200 (Tue, 17 Jul 2007) New Revision: 773

Modified:

   trunk/mysqlnd/mysqlnd.h
   trunk/mysqlnd/mysqlnd_enum_n_def.h
   trunk/mysqlnd/mysqlnd_palloc.c
   trunk/mysqlnd/mysqlnd_ps.c
   trunk/mysqlnd/mysqlnd_ps_codec.c
   trunk/mysqlnd/mysqlnd_result.c
   trunk/tests/ext/mysqli/009.phpt

Log:
Fixes of two crashes and memory problems. Now PS are less effective but work without problems. Data for bound variables has to be separated! If you wanted to use PS effectively then mysqli_stmt_get_result() is your friend.

Modified: trunk/mysqlnd/mysqlnd.h


  • trunk/mysqlnd/mysqlnd.h 2007-07-17 11:46:24 UTC (rev 772) +++ trunk/mysqlnd/mysqlnd.h 2007-07-17 12:36:34 UTC (rev 773)
    @@ -867,8 +867,8 @@

 /* There two should not be used from outside */

 void *	mysqlnd_palloc_get_zval(MYSQLND_THD_ZVAL_PCACHE * const cache, zend_bool *allocated);
-void	mysqlnd_palloc_zval_ptr_dtor(zval **zv, MYSQLND_THD_ZVAL_PCACHE * const cache, zend_bool ps,
-												 zend_bool *copy_ctor_called TSRMLS_DC);
+void	mysqlnd_palloc_zval_ptr_dtor(zval **zv, MYSQLND_THD_ZVAL_PCACHE * const cache,
+									 enum_mysqlnd_res_type type, zend_bool *copy_ctor_called TSRMLS_DC);
 
 
 

Modified: trunk/mysqlnd/mysqlnd_enum_n_def.h


  • trunk/mysqlnd/mysqlnd_enum_n_def.h 2007-07-17 11:46:24 UTC (rev 772) +++ trunk/mysqlnd/mysqlnd_enum_n_def.h 2007-07-17 12:36:34 UTC (rev 773)
    @@ -86,7 +86,8 @@
    typedef enum mysqlnd_res_type { MYSQLND_RES_NORMAL = 1, - MYSQLND_RES_PS + MYSQLND_RES_PS_BUF, + MYSQLND_RES_PS_UNBUF } enum_mysqlnd_res_type;

 typedef enum mysqlnd_option

Modified: trunk/mysqlnd/mysqlnd_palloc.c


  • trunk/mysqlnd/mysqlnd_palloc.c 2007-07-17 11:46:24 UTC (rev 772) +++ trunk/mysqlnd/mysqlnd_palloc.c 2007-07-17 12:36:34 UTC (rev 773)
    @@ -334,63 +334,55 @@

 /* {{{ mysqlnd_palloc_zval_ptr_dtor */
-void mysqlnd_palloc_zval_ptr_dtor(zval **zv, MYSQLND_THD_ZVAL_PCACHE * const thd_cache, zend_bool ps, - zend_bool *copy_ctor_called TSRMLS_DC) +void mysqlnd_palloc_zval_ptr_dtor(zval **zv, MYSQLND_THD_ZVAL_PCACHE * const thd_cache, + enum_mysqlnd_res_type type, zend_bool *copy_ctor_called TSRMLS_DC)  {

Do you need help?X

         MYSQLND_ZVAL_PCACHE *cache;
 #ifndef MYSQLND_SILENT

-	php_printf("[mysqlnd_palloc_zval_ptr_dtor %p] parent_block=%p last_in_block=%p *zv=%p ps=%d refc=%d\n",
+	php_printf("[mysqlnd_palloc_zval_ptr_dtor %p] parent_block=%p last_in_block=%p *zv=%p type=%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));
+				*zv, type, ZVAL_REFCOUNT(*zv));
 #endif
 	*copy_ctor_called = FALSE;
 	/* Check whether cache is used and the zval is from the cache */
 	if (!thd_cache || !(cache = thd_cache->parent) || ((char *)*zv < (char *)thd_cache->parent->block ||
 													   (char *)*zv > (char *)thd_cache->parent->last_in_block)) {
-		/* 
+		/*
 		  This zval is not from the cache block.
 		  Thus the refcount is -1 than of a zval from the cache,
 		  because the zvals from the cache are owned by it.
 		*/
-		if (ps == TRUE) {
-			ZVAL_REFCOUNT(*zv) = 1;		
+		if (type == MYSQLND_RES_PS_BUF || type == MYSQLND_RES_PS_UNBUF) {
+			ZVAL_REFCOUNT(*zv) = 1;			
 		} else if (ZVAL_REFCOUNT(*zv) > 1) {
-			if (ps == FALSE) {
-				/*
-				  Not a prepared statement, then we have to
Do you need more help?X
- call copy_ctor and then zval_ptr_dtor() + /* + Not a prepared statement, then we have to + call copy_ctor and then zval_ptr_dtor() - In Unicode mode the destruction of the zvals should not call - zval_copy_ctor() because then we will leak. - I suppose we can use UG(unicode) in mysqlnd.c when freeing a result set - to check if we need to call copy_ctor(). + In Unicode mode the destruction of the zvals should not call + zval_copy_ctor() because then we will leak. + I suppose we can use UG(unicode) in mysqlnd.c when freeing a result set + to check if we need to call copy_ctor(). - If the type is IS_UNICODE, which can happen with PHP6, then we don't - need to copy_ctor, as the data doesn't point to our internal buffers. - If it's string (in PHP5 always) and in PHP6 if data is binary, then - it still points to internal buffers and has to be copied. - */ - if (Z_TYPE_PP(zv) == IS_STRING) { - zval_copy_ctor(*zv); - } - *copy_ctor_called = TRUE; - } else { - /* For PS we copy stndup() the row buffers, so do nothing here */ + If the type is IS_UNICODE, which can happen with PHP6, then we don't + need to copy_ctor, as the data doesn't point to our internal buffers. + If it's string (in PHP5 always) and in PHP6 if data is binary, then + it still points to internal buffers and has to be copied. + */ + if (Z_TYPE_PP(zv) == IS_STRING) { + zval_copy_ctor(*zv); } + *copy_ctor_called = TRUE; } else { - if (ps == FALSE) { - /* - Prevent Zend from freeing PS allocated data. - Also don't null in Unicode mode as then the data doesn't point to - the internal buffers and we will leak if we do this trick.
Can we help you?X
- */ - if (Z_TYPE_PP(zv) == IS_STRING) { - ZVAL_NULL(*zv); - } - } else { - /* For PS we copy stndup() the row buffers, so do nothing here */ + /* + Prevent Zend from freeing PS allocated data. + Also don't null in Unicode mode as then the data doesn't point to + the internal buffers and we will leak if we do this trick. + */ + if (Z_TYPE_PP(zv) == IS_STRING) { + ZVAL_NULL(*zv); } } zval_ptr_dtor(zv);

Modified: trunk/mysqlnd/mysqlnd_ps.c


  • trunk/mysqlnd/mysqlnd_ps.c 2007-07-17 11:46:24 UTC (rev 772) +++ trunk/mysqlnd/mysqlnd_ps.c 2007-07-17 12:36:34 UTC (rev 773)
    @@ -94,7 +94,7 @@
    MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_PS_BUFFERED_SETS);
 	result = stmt->result;
-	result->type			= MYSQLND_RES_PS;
+	result->type			= MYSQLND_RES_PS_BUF;
 	result->m.fetch_row		= mysqlnd_fetch_stmt_row_buffered;
 	result->m.fetch_lengths	= NULL;/* makes no sense */
 	result->zval_cache		= mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache);

@@ -173,7 +173,7 @@
if ((result = result->m.store_result(result, conn, TRUE TSRMLS_CC))) { stmt->upsert_status.affected_rows = result->data->row_count; stmt->state = MYSQLND_STMT_PREPARED; - result->type = MYSQLND_RES_PS; + result->type = MYSQLND_RES_PS_BUF; } else { stmt->error_info = conn->error_info; stmt->state = MYSQLND_STMT_PREPARED;

@@ -318,7 +318,7 @@
 

                 result->conn = stmt_to_prepare->conn->m->get_reference(stmt_to_prepare->conn);  

  • result->type = MYSQLND_RES_PS; + result->type = MYSQLND_RES_PS_BUF;
 		if (FAIL == result->m.read_result_metadata(result, stmt_to_prepare->conn TSRMLS_CC) ||
 			FAIL == mysqlnd_stmt_prepare_read_eof(stmt_to_prepare TSRMLS_CC)) {

@@ -444,7 +444,7 @@
return PASS; } - stmt->result->type = MYSQLND_RES_PS; + stmt->result->type = MYSQLND_RES_PS_BUF; if (!stmt->result->conn) { /* For SHOW we don't create (bypasses PS in server)
@@ -512,6 +512,10 @@
if (stmt->result_bind) { zval **current_row = *result->data->data_cursor; for (i = 0; i < result->field_count; i++) { + /* Clean what we copied last time */ +#ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF + zval_dtor(stmt->result_bind[i].zv); +#endif
Can't find what you're looking for?X
/* copy the type */ if (stmt->result_bind[i].bound == TRUE) { if (Z_TYPE_P(current_row[i]) != IS_NULL) {

@@ -525,6 +529,9 @@
 
 						Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(current_row[i]);
 						stmt->result_bind[i].zv->value = current_row[i]->value;
+#ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
+						zval_copy_ctor(stmt->result_bind[i].zv);
+#endif
 					} else {
 						ZVAL_NULL(stmt->result_bind[i].zv);
 					}

@@ -592,9 +599,14 @@
in mysqlnd_unbuffered_free_last_data() */ +#ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF + zval_dtor(stmt->result_bind[i].zv); +#endif if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data)) ) { stmt->result_bind[i].zv->value = data->value;
-
+#ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
+						zval_copy_ctor(stmt->result_bind[i].zv);
+#endif						
 						if (
 							(Z_TYPE_P(data) == IS_STRING

 #if PHP_MAJOR_VERSION >= 6
@@ -671,7 +683,7 @@

         MYSQLND_INC_CONN_STATISTIC(&stmt->conn->stats, STAT_PS_UNBUFFERED_SETS);  

 	result					= stmt->result;
-	result->type 			= MYSQLND_RES_PS;
+	result->type 			= MYSQLND_RES_PS_UNBUF;
 	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 */

@@ -757,6 +769,9 @@
 
 					if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data)) ) {
 						stmt->result_bind[i].zv->value = data->value;
+#ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
+						zval_copy_ctor(stmt->result_bind[i].zv);
+#endif
 						if ((Z_TYPE_P(data) == IS_STRING
 #if PHP_MAJOR_VERSION >= 6
 							|| Z_TYPE_P(data) == IS_UNICODE

@@ -1080,7 +1095,7 @@
stmt->result_bind = result_bind; for (i = 0; i < stmt->field_count; i++) { /* Prevent from freeing */ - ZVAL_ADDREF(stmt->result_bind[i].zv); + ZVAL_ADDREF(stmt->result_bind[i].zv);
Don't know where to look next?X
/* Don't update is_ref !!! it's not our job Otherwise either 009.phpt or mysqli_stmt_bind_result.phpt
@@ -1358,7 +1373,9 @@
variable from our allocated zvals or we will face double-free */ if (ZVAL_REFCOUNT(stmt->result_bind[i].zv) > 1) { +#ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF zval_copy_ctor(stmt->result_bind[i].zv); +#endif zval_ptr_dtor(&stmt->result_bind[i].zv); } else { /*
@@ -1366,7 +1383,9 @@
later in free_result(). We need to remove the variable to which the user has lost reference. */ +#ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF ZVAL_NULL(stmt->result_bind[i].zv); +#endif zval_ptr_dtor(&stmt->result_bind[i].zv); } }

Modified: trunk/mysqlnd/mysqlnd_ps_codec.c


  • trunk/mysqlnd/mysqlnd_ps_codec.c 2007-07-17 11:46:24 UTC (rev 772) +++ trunk/mysqlnd/mysqlnd_ps_codec.c 2007-07-17 12:36:34 UTC (rev 773)
    @@ -417,9 +417,32 @@
    zend_bool as_unicode TSRMLS_DC) { unsigned long length= php_mysqlnd_net_field_length(row); - + ps_field_fetch_func func = NULL; + switch (length) { + case 8: + func = ps_fetch_int64; + break; + case 4: + case 3: + func = ps_fetch_int32; + break; + case 2: + func = ps_fetch_int16; + break; + case 1: + func = ps_fetch_int8; + break; + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Serious error. Length is %llu", length); + break; + } + if (func) { + func(zv, field, length, row, as_unicode TSRMLS_CC); + } +#if 0 /* Handle BIT here */ ZVAL_STRINGL(zv, (char *)*row, length, 1); +#endif

         (*row) += length;
 }
@@ -697,7 +720,12 @@

 					}
 					break;
 				case MYSQL_TYPE_VAR_STRING:
-					/* We have already converted it to string */
+					/*
+					  If the user uses refs, it could be that the type has
+					  has changed and we need to convert, again. Which is noop,
+					  if the type hasn't changed.
+					*/
+					convert_to_string_ex(&stmt->param_bind[i].zv);
 					{
 						unsigned int len = Z_STRLEN_P(data);
 						/* to is after p. The latter hasn't been moved */

Modified: trunk/mysqlnd/mysqlnd_result.c


  • trunk/mysqlnd/mysqlnd_result.c 2007-07-17 11:46:24 UTC (rev 772) +++ trunk/mysqlnd/mysqlnd_result.c 2007-07-17 12:36:34 UTC (rev 773)
    @@ -46,8 +46,7 @@
    MYSQLND_STATS *global_stats = result->conn? &result->conn->stats:NULL; for (i = 0; i < result->field_count; i++) { mysqlnd_palloc_zval_ptr_dtor(&(unbuf->last_row_data[i]), - result->zval_cache, - result->type == MYSQLND_RES_PS, + result->zval_cache, result->type, &copy_ctor_called TSRMLS_CC); if (copy_ctor_called) { ctor_called_count++;
    @@ -78,7 +77,6 @@
    { MYSQLND_THD_ZVAL_PCACHE *zval_cache = result->zval_cache; MYSQLND_RES_BUFFERED *set = result->data; - enum_mysqlnd_res_type result_type = result->type; unsigned int field_count = result->field_count; unsigned int row;

@@ -90,8 +88,7 @@

 		for (col = 0; col < field_count; col++) {
 			zend_bool copy_ctor_called;
 			mysqlnd_palloc_zval_ptr_dtor(&(current_row[col]), zval_cache,
-										 result_type == MYSQLND_RES_PS,
-										 ©_ctor_called TSRMLS_CC);
+										 result->type, ©_ctor_called TSRMLS_CC);
 			MYSQLND_INC_CONN_STATISTIC(NULL, copy_ctor_called? STAT_COPY_ON_WRITE_PERFORMED:
 															   STAT_COPY_ON_WRITE_SAVED);
 		}
Confused? Frustrated?X

Modified: trunk/tests/ext/mysqli/009.phpt


  • trunk/tests/ext/mysqli/009.phpt 2007-07-17 11:46:24 UTC (rev 772) +++ trunk/tests/ext/mysqli/009.phpt 2007-07-17 12:36:34 UTC (rev 773)
    @@ -27,17 +27,18 @@
    c4 bigint unsigned, c5 bigint unsigned, c6 bigint unsigned, - c7 bigint unsigned) ENGINE=" . $engine); + c7 bigint unsigned, + c8 bigint unsigned) ENGINE=" . $engine); if (!$rc) printf("[003] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
    • $rc = mysqli_query($link, "INSERT INTO test_bind_fetch (c2,c3,c4,c5,c6,c7) ".
    • "VALUES (-23,4.0,33333333333333,0,-333333333333,99.9)"); + $rc = mysqli_query($link, "INSERT INTO test_bind_fetch (c2,c3,c4,c5,c6,c7,c8) ". + "VALUES (-23,4.0,33333333333333,0,-333333333333,99.9,1234)"); if (!$rc) printf("[004] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
 	$stmt = mysqli_prepare($link, "SELECT * FROM test_bind_fetch");
-	mysqli_bind_result($stmt, $c1, $c2, $c3, $c4, $c5, $c6, $c7);
+	mysqli_bind_result($stmt, $c1, $c2, $c3, $c4, $c5, $c6, $c7, $c8);
Call Pantek today for Open Source Technical Support at 1-877-546-8934 - 24/7/365X
mysqli_execute($stmt); $rc = mysqli_fetch($stmt);
@@ -47,7 +48,8 @@
$c6 = 0; } } - $test = array($c1,$c2,$c3,$c4,$c5,$c6,$c7); + $c8 = 4567;// change this to test how mysqli/mysqlnd handles is_ref changing + $test = array($c1,$c2,$c3,$c4,$c5,$c6,$c7,$c8); var_dump($test);

@@ -75,7 +77,7 @@

 ?>  

 --EXPECTF--
-array(7) {
+array(8) {

   [0]=>
   int(5)
   [1]=>
@@ -90,12 +92,14 @@

   int(0)
   [6]=>
   int(100)
+ [7]=>
+ int(4567)
 }
 20123456
 3123456789
 done!
 --UEXPECTF--
-array(7) {
+array(8) {

   [0]=>
   int(5)
   [1]=>
@@ -110,7 +114,9 @@

   int(0)
   [6]=>
   int(100)
+ [7]=>
+ int(4567)
 }
 20123456
 3123456789
-done!
\ No newline at end of file
+done!

-- 
MySQL Code Commits Mailing List
For list archives: 
http://lists.mysql.com/commits
To unsubscribe:    
http://lists.mysql.com/commits?unsub=lists@pantek.com
Received on Tue Jul 17 08:36:45 2007

This archive was generated by hypermail 2.1.8 : Thu Aug 09 2007 - 19:07:16 EDT

Do you need help?X

Contact Us  Legal Notices  Order Services Online 
Pantek Home  Privacy Policy  IT news  Site Map  Pantek Library