diff options
Diffstat (limited to 'ext/mysqlnd/mysqlnd_ps_codec.c')
| -rw-r--r-- | ext/mysqlnd/mysqlnd_ps_codec.c | 221 | 
1 files changed, 111 insertions, 110 deletions
| diff --git a/ext/mysqlnd/mysqlnd_ps_codec.c b/ext/mysqlnd/mysqlnd_ps_codec.c index def140ad89..da2436310e 100644 --- a/ext/mysqlnd/mysqlnd_ps_codec.c +++ b/ext/mysqlnd/mysqlnd_ps_codec.c @@ -1,6 +1,6 @@  /*    +----------------------------------------------------------------------+ -  | PHP Version 5                                                        | +  | PHP Version 7                                                        |    +----------------------------------------------------------------------+    | Copyright (c) 2006-2016 The PHP Group                                |    +----------------------------------------------------------------------+ @@ -12,13 +12,12 @@    | obtain it through the world-wide-web, please send a note to          |    | license@php.net so we can mail you a copy immediately.               |    +----------------------------------------------------------------------+ -  | Authors: Andrey Hristov <andrey@mysql.com>                           | -  |          Ulf Wendel <uwendel@mysql.com>                              | -  |          Georg Richter <georg@mysql.com>                             | +  | Authors: Andrey Hristov <andrey@php.net>                             | +  |          Ulf Wendel <uw@php.net>                                     | +  |          Georg Richter <georg@php.net>                               |    +----------------------------------------------------------------------+  */ -/* $Id$ */  #include "php.h"  #include "mysqlnd.h"  #include "mysqlnd_wireprotocol.h" @@ -42,7 +41,7 @@ enum mysqlnd_timestamp_type  struct st_mysqlnd_time  {    unsigned int  year, month, day, hour, minute, second; -  unsigned long second_part; +  zend_ulong second_part;    zend_bool     neg;    enum mysqlnd_timestamp_type time_type;  }; @@ -56,7 +55,7 @@ struct st_mysqlnd_perm_bind mysqlnd_ps_fetch_functions[MYSQL_TYPE_LAST + 1];  /* {{{ ps_fetch_from_1_to_8_bytes */  void  ps_fetch_from_1_to_8_bytes(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, -						   zend_uchar ** row, unsigned int byte_count TSRMLS_DC) +						   zend_uchar ** row, unsigned int byte_count)  {  	char tmp[22];  	size_t tmp_len = 0; @@ -77,18 +76,19 @@ ps_fetch_from_1_to_8_bytes(zval * zv, const MYSQLND_FIELD * const field, unsigne  			case 1:uval = (uint64_t) uint1korr(*row);break;  		} -#if SIZEOF_LONG==4 +#if SIZEOF_ZEND_LONG==4  		if (uval > INT_MAX) {  			DBG_INF("stringify");  			tmp_len = sprintf((char *)&tmp, MYSQLND_LLU_SPEC, uval); -		} else  +		} else  #endif /* #if SIZEOF_LONG==4 */  		{  			if (byte_count < 8 || uval <= L64(9223372036854775807)) { -				ZVAL_LONG(zv, (long) uval); /* the cast is safe, we are in the range */ +				ZVAL_LONG(zv, (zend_long) uval); /* the cast is safe, we are in the range */  			} else {  				DBG_INF("stringify");  				tmp_len = sprintf((char *)&tmp, MYSQLND_LLU_SPEC, uval); +				DBG_INF_FMT("value=%s", tmp);  			}  		}  	} else { @@ -106,19 +106,19 @@ ps_fetch_from_1_to_8_bytes(zval * zv, const MYSQLND_FIELD * const field, unsigne  			case 1:lval = (int64_t) *(int8_t*)*row;break;  		} -#if SIZEOF_LONG==4 +#if SIZEOF_ZEND_LONG==4  		if ((L64(2147483647) < (int64_t) lval) || (L64(-2147483648) > (int64_t) lval)) {  			DBG_INF("stringify");  			tmp_len = sprintf((char *)&tmp, MYSQLND_LL_SPEC, lval);  		} else  #endif /* SIZEOF */  		{ -			ZVAL_LONG(zv, (long) lval); /* the cast is safe, we are in the range */ +			ZVAL_LONG(zv, (zend_long) lval); /* the cast is safe, we are in the range */  		}  	}  	if (tmp_len) { -		ZVAL_STRINGL(zv, tmp, tmp_len, 1); +		ZVAL_STRINGL(zv, tmp, tmp_len);  	}  	(*row)+= byte_count;  	DBG_VOID_RETURN; @@ -128,7 +128,7 @@ ps_fetch_from_1_to_8_bytes(zval * zv, const MYSQLND_FIELD * const field, unsigne  /* {{{ ps_fetch_null */  static void -ps_fetch_null(zval *zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC) +ps_fetch_null(zval *zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row)  {  	ZVAL_NULL(zv);  } @@ -137,43 +137,43 @@ ps_fetch_null(zval *zv, const MYSQLND_FIELD * const field, unsigned int pack_len  /* {{{ ps_fetch_int8 */  static void -ps_fetch_int8(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC) +ps_fetch_int8(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row)  { -	ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, 1 TSRMLS_CC); +	ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, 1);  }  /* }}} */  /* {{{ ps_fetch_int16 */  static void -ps_fetch_int16(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC) +ps_fetch_int16(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row)  { -	ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, 2 TSRMLS_CC); +	ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, 2);  }  /* }}} */  /* {{{ ps_fetch_int32 */  static void -ps_fetch_int32(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC) +ps_fetch_int32(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row)  { -	ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, 4 TSRMLS_CC); +	ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, 4);  }  /* }}} */  /* {{{ ps_fetch_int64 */  static void -ps_fetch_int64(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC) +ps_fetch_int64(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row)  { -	ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, 8 TSRMLS_CC); +	ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, 8);  }  /* }}} */  /* {{{ ps_fetch_float */  static void -ps_fetch_float(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC) +ps_fetch_float(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row)  {  	float fval;  	double dval; @@ -196,7 +196,7 @@ ps_fetch_float(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_l  /* {{{ ps_fetch_double */  static void -ps_fetch_double(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC) +ps_fetch_double(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row)  {  	double value;  	DBG_ENTER("ps_fetch_double"); @@ -211,10 +211,10 @@ ps_fetch_double(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_  /* {{{ ps_fetch_time */  static void -ps_fetch_time(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC) +ps_fetch_time(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row)  {  	struct st_mysqlnd_time t; -	unsigned long length; /* First byte encodes the length*/ +	zend_ulong length; /* First byte encodes the length*/  	char * value;  	DBG_ENTER("ps_fetch_time"); @@ -224,11 +224,11 @@ ps_fetch_time(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_le  		t.time_type = MYSQLND_TIMESTAMP_TIME;  		t.neg			= (zend_bool) to[0]; -		t.day			= (unsigned long) sint4korr(to+1); +		t.day			= (zend_ulong) sint4korr(to+1);  		t.hour			= (unsigned int) to[5];  		t.minute		= (unsigned int) to[6];  		t.second		= (unsigned int) to[7]; -		t.second_part	= (length > 8) ? (unsigned long) sint4korr(to+8) : 0; +		t.second_part	= (length > 8) ? (zend_ulong) sint4korr(to+8) : 0;  		t.year			= t.month= 0;  		if (t.day) {  			/* Convert days to hours at once */ @@ -245,7 +245,7 @@ ps_fetch_time(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_le  	length = mnd_sprintf(&value, 0, "%s%02u:%02u:%02u", (t.neg ? "-" : ""), t.hour, t.minute, t.second);  	DBG_INF_FMT("%s", value); -	ZVAL_STRINGL(zv, value, length, 1); +	ZVAL_STRINGL(zv, value, length);  	mnd_sprintf_free(value);  	DBG_VOID_RETURN;  } @@ -254,10 +254,10 @@ ps_fetch_time(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_le  /* {{{ ps_fetch_date */  static void -ps_fetch_date(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC) +ps_fetch_date(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row)  {  	struct st_mysqlnd_time t = {0}; -	unsigned long length; /* First byte encodes the length*/ +	zend_ulong length; /* First byte encodes the length*/  	char * value;  	DBG_ENTER("ps_fetch_date"); @@ -282,7 +282,7 @@ ps_fetch_date(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_le  	length = mnd_sprintf(&value, 0, "%04u-%02u-%02u", t.year, t.month, t.day);  	DBG_INF_FMT("%s", value); -	ZVAL_STRINGL(zv, value, length, 1); +	ZVAL_STRINGL(zv, value, length);  	mnd_sprintf_free(value);  	DBG_VOID_RETURN;  } @@ -291,10 +291,10 @@ ps_fetch_date(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_le  /* {{{ ps_fetch_datetime */  static void -ps_fetch_datetime(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC) +ps_fetch_datetime(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row)  {  	struct st_mysqlnd_time t; -	unsigned long length; /* First byte encodes the length*/ +	zend_ulong length; /* First byte encodes the length*/  	char * value;  	DBG_ENTER("ps_fetch_datetime"); @@ -315,7 +315,7 @@ ps_fetch_datetime(zval * zv, const MYSQLND_FIELD * const field, unsigned int pac  		} else {  			t.hour = t.minute = t.second= 0;  		} -		t.second_part = (length > 7) ? (unsigned long) sint4korr(to+7) : 0; +		t.second_part = (length > 7) ? (zend_ulong) sint4korr(to+7) : 0;  		(*row)+= length;  	} else { @@ -326,7 +326,7 @@ ps_fetch_datetime(zval * zv, const MYSQLND_FIELD * const field, unsigned int pac  	length = mnd_sprintf(&value, 0, "%04u-%02u-%02u %02u:%02u:%02u", t.year, t.month, t.day, t.hour, t.minute, t.second);  	DBG_INF_FMT("%s", value); -	ZVAL_STRINGL(zv, value, length, 1); +	ZVAL_STRINGL(zv, value, length);  	mnd_sprintf_free(value);  	DBG_VOID_RETURN;  } @@ -335,17 +335,17 @@ ps_fetch_datetime(zval * zv, const MYSQLND_FIELD * const field, unsigned int pac  /* {{{ ps_fetch_string */  static void -ps_fetch_string(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC) +ps_fetch_string(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row)  {  	/*  	  For now just copy, before we make it possible  	  to write \0 to the row buffer  	*/ -	const unsigned long length = php_mysqlnd_net_field_length(row); +	const zend_ulong length = php_mysqlnd_net_field_length(row);  	DBG_ENTER("ps_fetch_string");  	DBG_INF_FMT("len = %lu", length);  	DBG_INF("copying from the row buffer"); -	ZVAL_STRINGL(zv, (char *)*row, length, 1); +	ZVAL_STRINGL(zv, (char *)*row, length);  	(*row) += length;  	DBG_VOID_RETURN; @@ -355,10 +355,10 @@ ps_fetch_string(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_  /* {{{ ps_fetch_bit */  static void -ps_fetch_bit(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC) +ps_fetch_bit(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row)  { -	unsigned long length = php_mysqlnd_net_field_length(row); -	ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, length TSRMLS_CC); +	zend_ulong length = php_mysqlnd_net_field_length(row); +	ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, length);  }  /* }}} */ @@ -514,16 +514,13 @@ void _mysqlnd_init_ps_fetch_subsystem()  /* {{{ mysqlnd_stmt_copy_it */  static enum_func_status -mysqlnd_stmt_copy_it(zval *** copies, zval * original, unsigned int param_count, unsigned int current TSRMLS_DC) +mysqlnd_stmt_copy_it(zval ** copies, zval * original, unsigned int param_count, unsigned int current)  {  	if (!*copies) { -		*copies = mnd_ecalloc(param_count, sizeof(zval *)); +		*copies = mnd_ecalloc(param_count, sizeof(zval));  	}  	if (*copies) { -		MAKE_STD_ZVAL((*copies)[current]); -		*(*copies)[current] = *original; -		Z_SET_REFCOUNT_P((*copies)[current], 1); -		zval_copy_ctor((*copies)[current]); +		ZVAL_COPY(&(*copies)[current], original);  		return PASS;  	}  	return FAIL; @@ -533,14 +530,12 @@ mysqlnd_stmt_copy_it(zval *** copies, zval * original, unsigned int param_count,  /* {{{ mysqlnd_stmt_free_copies */  static void -mysqlnd_stmt_free_copies(MYSQLND_STMT_DATA * stmt, zval ** copies TSRMLS_DC) +mysqlnd_stmt_free_copies(MYSQLND_STMT_DATA * stmt, zval *copies)  {  	if (copies) {  		unsigned int i;  		for (i = 0; i < stmt->param_count; i++) { -			if (copies[i]) { -				zval_ptr_dtor(&copies[i]); -			} +			zval_ptr_dtor(&copies[i]);  		}  		mnd_efree(copies);  	} @@ -550,7 +545,7 @@ mysqlnd_stmt_free_copies(MYSQLND_STMT_DATA * stmt, zval ** copies TSRMLS_DC)  /* {{{ mysqlnd_stmt_execute_check_n_enlarge_buffer */  static enum_func_status -mysqlnd_stmt_execute_check_n_enlarge_buffer(zend_uchar **buf, zend_uchar **p, size_t * buf_len, zend_uchar * const provided_buffer, size_t needed_bytes TSRMLS_DC) +mysqlnd_stmt_execute_check_n_enlarge_buffer(zend_uchar **buf, zend_uchar **p, size_t * buf_len, zend_uchar * const provided_buffer, size_t needed_bytes)  {  	const size_t overalloc = 5;  	size_t left = (*buf_len - (*p - *buf)); @@ -578,39 +573,36 @@ mysqlnd_stmt_execute_check_n_enlarge_buffer(zend_uchar **buf, zend_uchar **p, si  /* {{{ mysqlnd_stmt_execute_prepare_param_types */  static enum_func_status -mysqlnd_stmt_execute_prepare_param_types(MYSQLND_STMT_DATA * stmt, zval *** copies_param, int * resend_types_next_time TSRMLS_DC) +mysqlnd_stmt_execute_prepare_param_types(MYSQLND_STMT_DATA * stmt, zval ** copies_param, int * resend_types_next_time)  {  	unsigned int i;  	DBG_ENTER("mysqlnd_stmt_execute_prepare_param_types");  	for (i = 0; i < stmt->param_count; i++) {  		short current_type = stmt->param_bind[i].type; +		zval *parameter = &stmt->param_bind[i].zv; -		if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_NULL && (current_type == MYSQL_TYPE_LONG || current_type == MYSQL_TYPE_LONGLONG)) { -			zval ** copies; +		ZVAL_DEREF(parameter); +		if (!Z_ISNULL_P(parameter) && (current_type == MYSQL_TYPE_LONG || current_type == MYSQL_TYPE_LONGLONG)) {  			/* always copy the var, because we do many conversions */ -			if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG && -				PASS != mysqlnd_stmt_copy_it(copies_param, stmt->param_bind[i].zv, stmt->param_count, i TSRMLS_CC)) +			if (Z_TYPE_P(parameter) != IS_LONG && +				PASS != mysqlnd_stmt_copy_it(copies_param, parameter, stmt->param_count, i))  			{  				SET_OOM_ERROR(*stmt->error_info);  				goto end;  			} -			copies = *copies_param;  			/*  			  if it doesn't fit in a long send it as a string.  			  Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX  			*/ -			if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG) { -				zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv; +			if (Z_TYPE_P(parameter) != IS_LONG) { +				zval *tmp_data = (*copies_param && !Z_ISUNDEF((*copies_param)[i]))? &(*copies_param)[i]: parameter;  				/*  				  Because converting to double and back to long can lead -				  to losing precision we need second variable. Conversion to double is to see if  +				  to losing precision we need second variable. Conversion to double is to see if  				  value is too big for a long. As said, precision could be lost.  				*/ -				zval *tmp_data_copy; -				MAKE_STD_ZVAL(tmp_data_copy); -				*tmp_data_copy = *tmp_data; -				Z_SET_REFCOUNT_P(tmp_data_copy, 1); -				zval_copy_ctor(tmp_data_copy); +				zval tmp_data_copy; +				ZVAL_COPY(&tmp_data_copy, tmp_data);  				convert_to_double_ex(&tmp_data_copy);  				/* @@ -618,11 +610,11 @@ mysqlnd_stmt_execute_prepare_param_types(MYSQLND_STMT_DATA * stmt, zval *** copi  				  Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX  				  We do transformation here, which will be used later when sending types. The code later relies on this.  				*/ -				if (Z_DVAL_P(tmp_data_copy) > LONG_MAX || Z_DVAL_P(tmp_data_copy) < LONG_MIN) { +				if (Z_DVAL(tmp_data_copy) > ZEND_LONG_MAX || Z_DVAL(tmp_data_copy) < ZEND_LONG_MIN) {  					stmt->send_types_to_server = *resend_types_next_time = 1; -					convert_to_string_ex(&tmp_data); +					convert_to_string_ex(tmp_data);  				} else { -					convert_to_long_ex(&tmp_data); +					convert_to_long_ex(tmp_data);  				}  				zval_ptr_dtor(&tmp_data_copy); @@ -638,24 +630,26 @@ end:  /* {{{ mysqlnd_stmt_execute_store_types */  static void -mysqlnd_stmt_execute_store_types(MYSQLND_STMT_DATA * stmt, zval ** copies, zend_uchar ** p) +mysqlnd_stmt_execute_store_types(MYSQLND_STMT_DATA * stmt, zval * copies, zend_uchar ** p)  {  	unsigned int i;  	for (i = 0; i < stmt->param_count; i++) {  		short current_type = stmt->param_bind[i].type; +		zval *parameter = &stmt->param_bind[i].zv;  		/* our types are not unsigned */ -#if SIZEOF_LONG==8   +#if SIZEOF_ZEND_LONG==8  		if (current_type == MYSQL_TYPE_LONG) {  			current_type = MYSQL_TYPE_LONGLONG;  		}  #endif -		if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_NULL && (current_type == MYSQL_TYPE_LONG || current_type == MYSQL_TYPE_LONGLONG)) { +		ZVAL_DEREF(parameter); +		if (!Z_ISNULL_P(parameter) && (current_type == MYSQL_TYPE_LONG || current_type == MYSQL_TYPE_LONGLONG)) {  			/*  			  if it doesn't fit in a long send it as a string.  			  Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX  			*/ -			if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG) { -				const zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv; +			if (Z_TYPE_P(parameter) != IS_LONG) { +				const zval *tmp_data = (copies && !Z_ISUNDEF(copies[i]))? &copies[i] : parameter;  				/*  				  In case of IS_LONG we do nothing, it is ok, in case of string, we just need to set current_type.  				  The actual transformation has been performed several dozens line above. @@ -680,28 +674,33 @@ mysqlnd_stmt_execute_store_types(MYSQLND_STMT_DATA * stmt, zval ** copies, zend_  /* {{{ mysqlnd_stmt_execute_calculate_param_values_size */  static enum_func_status -mysqlnd_stmt_execute_calculate_param_values_size(MYSQLND_STMT_DATA * stmt, zval *** copies_param, size_t * data_size TSRMLS_DC) +mysqlnd_stmt_execute_calculate_param_values_size(MYSQLND_STMT_DATA * stmt, zval ** copies_param, size_t * data_size)  {  	unsigned int i;  	DBG_ENTER("mysqlnd_stmt_execute_calculate_param_values_size");  	for (i = 0; i < stmt->param_count; i++) {  		unsigned short is_longlong = 0;  		unsigned int j; -		zval *the_var = stmt->param_bind[i].zv; +		zval *bind_var, *the_var = &stmt->param_bind[i].zv; -		if (!the_var || (stmt->param_bind[i].type != MYSQL_TYPE_LONG_BLOB && Z_TYPE_P(the_var) == IS_NULL)) { +		bind_var = the_var; +		ZVAL_DEREF(the_var); +		if ((stmt->param_bind[i].type != MYSQL_TYPE_LONG_BLOB && Z_TYPE_P(the_var) == IS_NULL)) {  			continue;  		} -		for (j = i + 1; j < stmt->param_count; j++) { -			if (stmt->param_bind[j].zv == the_var) { -				/* Double binding of the same zval, make a copy */ -				if (!*copies_param || !(*copies_param)[i]) { -					if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i TSRMLS_CC)) { -						SET_OOM_ERROR(*stmt->error_info); -						goto end; + +		if (Z_ISREF_P(bind_var)) { +			for (j = i + 1; j < stmt->param_count; j++) { +				if (Z_ISREF(stmt->param_bind[j].zv) && Z_REFVAL(stmt->param_bind[j].zv) == the_var) { +					/* Double binding of the same zval, make a copy */ +					if (!*copies_param || Z_ISUNDEF((*copies_param)[i])) { +						if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i)) { +							SET_OOM_ERROR(*stmt->error_info); +							goto end; +						}  					} +					break;  				} -				break;  			}  		} @@ -709,8 +708,8 @@ mysqlnd_stmt_execute_calculate_param_values_size(MYSQLND_STMT_DATA * stmt, zval  			case MYSQL_TYPE_DOUBLE:  				*data_size += 8;  				if (Z_TYPE_P(the_var) != IS_DOUBLE) { -					if (!*copies_param || !(*copies_param)[i]) { -						if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i TSRMLS_CC)) { +					if (!*copies_param || Z_ISUNDEF((*copies_param)[i])) { +						if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i)) {  							SET_OOM_ERROR(*stmt->error_info);  							goto end;  						} @@ -722,11 +721,11 @@ mysqlnd_stmt_execute_calculate_param_values_size(MYSQLND_STMT_DATA * stmt, zval  				/* fall-through */  			case MYSQL_TYPE_LONG:  				{ -					zval *tmp_data = (*copies_param && (*copies_param)[i])? (*copies_param)[i]: stmt->param_bind[i].zv; +					zval *tmp_data = (*copies_param && !Z_ISUNDEF((*copies_param)[i]))? &(*copies_param)[i]: the_var;  					if (Z_TYPE_P(tmp_data) == IS_STRING) {  						goto use_string;  					} -					convert_to_long_ex(&tmp_data); +					convert_to_long_ex(tmp_data);  				}  				*data_size += 4 + is_longlong;  				break; @@ -744,15 +743,15 @@ mysqlnd_stmt_execute_calculate_param_values_size(MYSQLND_STMT_DATA * stmt, zval  use_string:  				*data_size += 8; /* max 8 bytes for size */  				if (Z_TYPE_P(the_var) != IS_STRING) { -					if (!*copies_param || !(*copies_param)[i]) { -						if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i TSRMLS_CC)) { +					if (!*copies_param || Z_ISUNDEF((*copies_param)[i])) { +						if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i)) {  							SET_OOM_ERROR(*stmt->error_info);  							goto end;  						}  					} -					the_var = (*copies_param)[i]; +					the_var = &((*copies_param)[i]);  				} -				convert_to_string_ex(&the_var); +				convert_to_string_ex(the_var);  				*data_size += Z_STRLEN_P(the_var);  				break;  		} @@ -766,18 +765,21 @@ end:  /* {{{ mysqlnd_stmt_execute_store_param_values */  static void -mysqlnd_stmt_execute_store_param_values(MYSQLND_STMT_DATA * stmt, zval ** copies, zend_uchar * buf, zend_uchar ** p, size_t null_byte_offset) +mysqlnd_stmt_execute_store_param_values(MYSQLND_STMT_DATA * stmt, zval * copies, zend_uchar * buf, zend_uchar ** p, size_t null_byte_offset)  {  	unsigned int i;  	for (i = 0; i < stmt->param_count; i++) { -		zval * data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv; +		zval *data, *parameter = &stmt->param_bind[i].zv; + +		ZVAL_DEREF(parameter); +		data = (copies && !Z_ISUNDEF(copies[i]))? &copies[i]: parameter;  		/* Handle long data */ -		if (stmt->param_bind[i].zv && Z_TYPE_P(data) == IS_NULL) { +		if (!Z_ISUNDEF_P(parameter) && Z_TYPE_P(data) == IS_NULL) {  			(buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7));  		} else {  			switch (stmt->param_bind[i].type) {  				case MYSQL_TYPE_DOUBLE: -					convert_to_double_ex(&data); +					convert_to_double_ex(data);  					float8store(*p, Z_DVAL_P(data));  					(*p) += 8;  					break; @@ -828,13 +830,12 @@ send_string:  /* {{{ mysqlnd_stmt_execute_store_params */  static enum_func_status -mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar **p, size_t *buf_len  TSRMLS_DC) +mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar **p, size_t *buf_len )  {  	MYSQLND_STMT_DATA * stmt = s->data; -	unsigned int i = 0;  	zend_uchar * provided_buffer = *buf;  	size_t data_size = 0; -	zval **copies = NULL;/* if there are different types */ +	zval *copies = NULL;/* if there are different types */  	enum_func_status ret = FAIL;  	int resend_types_next_time = 0;  	size_t null_byte_offset; @@ -843,7 +844,7 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar  	{  		unsigned int null_count = (stmt->param_count + 7) / 8; -		if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, null_count TSRMLS_CC)) { +		if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, null_count)) {  			SET_OOM_ERROR(*stmt->error_info);  			goto end;  		} @@ -861,7 +862,7 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar  	  won't expect it and interpret the value as 0. Thus we need to resend the types, if any such values  	  occur, and force resend for the next execution.  	*/ -	if (FAIL == mysqlnd_stmt_execute_prepare_param_types(stmt, &copies, &resend_types_next_time TSRMLS_CC)) { +	if (FAIL == mysqlnd_stmt_execute_prepare_param_types(stmt, &copies, &resend_types_next_time)) {  		goto end;  	} @@ -869,7 +870,7 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar  	(*p)++;  	if (stmt->send_types_to_server) { -		if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, stmt->param_count * 2 TSRMLS_CC)) { +		if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, stmt->param_count * 2)) {  			SET_OOM_ERROR(*stmt->error_info);  			goto end;  		} @@ -880,12 +881,12 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar  /* 2. Store data */  	/* 2.1 Calculate how much space we need */ -	if (FAIL == mysqlnd_stmt_execute_calculate_param_values_size(stmt, &copies, &data_size TSRMLS_CC)) { +	if (FAIL == mysqlnd_stmt_execute_calculate_param_values_size(stmt, &copies, &data_size)) {  		goto end;  	}  	/* 2.2 Enlarge the buffer, if needed */ -	if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, data_size TSRMLS_CC)) { +	if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, data_size)) {  		SET_OOM_ERROR(*stmt->error_info);  		goto end;  	} @@ -895,7 +896,7 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar  	ret = PASS;  end: -	mysqlnd_stmt_free_copies(stmt, copies TSRMLS_CC); +	mysqlnd_stmt_free_copies(stmt, copies);  	DBG_INF_FMT("ret=%s", ret == PASS? "PASS":"FAIL");  	DBG_RETURN(ret); @@ -905,7 +906,7 @@ end:  /* {{{ mysqlnd_stmt_execute_generate_request */  enum_func_status -mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * const s, zend_uchar ** request, size_t *request_len, zend_bool * free_buffer TSRMLS_DC) +mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * const s, zend_uchar ** request, size_t *request_len, zend_bool * free_buffer)  {  	MYSQLND_STMT_DATA * stmt = s->data;  	zend_uchar	*p = stmt->execute_cmd_buffer.buffer, @@ -923,12 +924,12 @@ mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * const s, zend_uchar ** requ  	p++;  	/* Make it all zero */ -	int4store(p, 0);  +	int4store(p, 0);  	int1store(p, 1); /* and send 1 for iteration count */  	p+= 4; -	ret = mysqlnd_stmt_execute_store_params(s, &cmd_buffer, &p, &cmd_buffer_length TSRMLS_CC); +	ret = mysqlnd_stmt_execute_store_params(s, &cmd_buffer, &p, &cmd_buffer_length);  	*free_buffer = (cmd_buffer != stmt->execute_cmd_buffer.buffer);  	*request_len = (p - cmd_buffer); | 
