示例#1
0
/* {{{ mysqlnd_stmt_execute_store_params */
static void
mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar **p,
								  size_t *buf_len, unsigned int null_byte_offset TSRMLS_DC)
{
	MYSQLND_STMT_DATA * stmt = s->data;
	unsigned int i = 0;
	size_t left = (*buf_len - (*p - *buf));
	size_t data_size = 0;
	zval **copies = NULL;/* if there are different types */

/* 1. Store type information */
	if (stmt->send_types_to_server) {

		/* 2 bytes per type, and leave 20 bytes for future use */
		if (left < ((stmt->param_count * 2) + 20)) {
			unsigned int offset = *p - *buf;
			zend_uchar *tmp_buf;
			*buf_len = offset + stmt->param_count * 2 + 20;
			tmp_buf = mnd_emalloc(*buf_len);
			memcpy(tmp_buf, *buf, offset);
			*buf = tmp_buf;
			
			/* Update our pos pointer */
			*p = *buf + offset;
		}
		for (i = 0; i < stmt->param_count; i++) {
			/* our types are not unsigned */
#if SIZEOF_LONG==8  
			if (stmt->param_bind[i].type == MYSQL_TYPE_LONG) {
				stmt->param_bind[i].type = MYSQL_TYPE_LONGLONG;
			}
#endif
			int2store(*p, stmt->param_bind[i].type);
			*p+= 2;
		}
	}

/* 2. Store data */
	/* 2.1 Calculate how much space we need */
	for (i = 0; i < stmt->param_count; i++) {
		unsigned int j;
		zval *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)) {
			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 */
				mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC);
				break; 
			}
		}

		switch (stmt->param_bind[i].type) {
			case MYSQL_TYPE_DOUBLE:
				data_size += 8;
				if (Z_TYPE_P(the_var) != IS_DOUBLE) {
					if (!copies || !copies[i]) {
						mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC);
					}
				}
				break;
#if SIZEOF_LONG==8  
			case MYSQL_TYPE_LONGLONG:
				data_size += 8;
#elif SIZEOF_LONG==4
			case MYSQL_TYPE_LONG:
				data_size += 4;
#else
#error "Should not happen"
#endif
				if (Z_TYPE_P(the_var) != IS_LONG) {
					if (!copies || !copies[i]) {
						mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC);
					}
				}
				break;
			case MYSQL_TYPE_LONG_BLOB:
				if (!(stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED)) {
					/*
					  User hasn't sent anything, we will send empty string.
					  Empty string has length of 0, encoded in 1 byte. No real
					  data will follows after it.
					*/
					data_size++;
				}
				break;
			case MYSQL_TYPE_VAR_STRING:
				data_size += 8; /* max 8 bytes for size */
#if PHP_MAJOR_VERSION < 6
				if (Z_TYPE_P(the_var) != IS_STRING)
#elif PHP_MAJOR_VERSION >= 6
				if (Z_TYPE_P(the_var) != IS_STRING || Z_TYPE_P(the_var) == IS_UNICODE)
#endif
				{
					if (!copies || !copies[i]) {
						mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC);
					}
					the_var = copies[i];
#if PHP_MAJOR_VERSION >= 6
					if (Z_TYPE_P(the_var) == IS_UNICODE) {
						zval_unicode_to_string_ex(the_var, UG(utf8_conv) TSRMLS_CC);
					}
#endif
				}
				convert_to_string_ex(&the_var);
				data_size += Z_STRLEN_P(the_var);
				break;
		}

	}

	/* 2.2 Enlarge the buffer, if needed */
	left = (*buf_len - (*p - *buf));
	if (left < data_size) {
		unsigned int offset = *p - *buf;
		zend_uchar *tmp_buf;
		*buf_len = offset + data_size + 10; /* Allocate + 10 for safety */
		tmp_buf = mnd_emalloc(*buf_len);
		memcpy(tmp_buf, *buf, offset);
		*buf = tmp_buf;
		/* Update our pos pointer */
		*p = *buf + offset;	
	}

	/* 2.3 Store the actual data */
	for (i = 0; i < stmt->param_count; i++) {
		zval *data = copies && copies[i]? copies[i]: stmt->param_bind[i].zv;
		/* Handle long data */
		if (stmt->param_bind[i].zv && 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);
					float8store(*p, Z_DVAL_P(data));
					(*p) += 8;
					break;
#if SIZEOF_LONG==8  
				case MYSQL_TYPE_LONGLONG:
					convert_to_long_ex(&data);
					int8store(*p, Z_LVAL_P(data));
					(*p) += 8;
					break;
#elif SIZEOF_LONG==4
				case MYSQL_TYPE_LONG:
					convert_to_long_ex(&data);
					int4store(*p, Z_LVAL_P(data));
					(*p) += 4;
					break;
#else
#error "Should not happen"
#endif
				case MYSQL_TYPE_LONG_BLOB:
					if (stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED) {
						stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
					} else {
						/* send_long_data() not called, send empty string */
						*p = php_mysqlnd_net_store_length(*p, 0);
					}
					break;
				case MYSQL_TYPE_VAR_STRING:{
						unsigned int len = Z_STRLEN_P(data);
						/* to is after p. The latter hasn't been moved */
						*p = php_mysqlnd_net_store_length(*p, len);
						memcpy(*p, Z_STRVAL_P(data), len);
						(*p) += len;
					}
					break;
				default:
					/* Won't happen, but set to NULL */
					(*buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7));
					break;
			}
		}
	}
	if (copies) {
		for (i = 0; i < stmt->param_count; i++) {
			if (copies[i]) {
				zval_ptr_dtor(&copies[i]);
			}
		}
		mnd_efree(copies);	
	}
}
static void convert_froma_string(MYSQL_BIND *r_param, char *buffer, size_t len)
{
  int error= 0;
  switch (r_param->buffer_type)
  {
    case MYSQL_TYPE_TINY:
    {
      longlong val= my_atoll(buffer, buffer + len, &error);
      *r_param->error= error ? 1 : r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX8) : NUMERIC_TRUNCATION(val, INT_MIN8, INT_MAX8) || error > 0;
      int1store(r_param->buffer, (uchar) val);
      r_param->buffer_length= sizeof(uchar);
    }
    break;
    case MYSQL_TYPE_YEAR:
    case MYSQL_TYPE_SHORT:
    {
      longlong val= my_atoll(buffer, buffer + len, &error);
      *r_param->error= error ? 1 : r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX16) : NUMERIC_TRUNCATION(val, INT_MIN16, INT_MAX16) || error > 0;
      shortstore(r_param->buffer, (short)val);
      r_param->buffer_length= sizeof(short);
    } 
    break;
    case MYSQL_TYPE_LONG:
    {
      longlong val= my_atoll(buffer, buffer + len, &error);
      *r_param->error=error ? 1 : r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX32) : NUMERIC_TRUNCATION(val, INT_MIN32, INT_MAX32) || error > 0;
      longstore(r_param->buffer, (int32)val);
      r_param->buffer_length= sizeof(uint32);
    } 
    break;
    case MYSQL_TYPE_LONGLONG:
    {
      longlong val= my_atoll(buffer, buffer + len, &error);
      *r_param->error= error > 0; /* no need to check for truncation */
      longlongstore(r_param->buffer, val);
      r_param->buffer_length= sizeof(longlong);
    } 
    break;
    case MYSQL_TYPE_DOUBLE:
    {
      double val= my_atod(buffer, buffer + len, &error);
      *r_param->error= error > 0; /* no need to check for truncation */
      float8store(r_param->buffer, val);
      r_param->buffer_length= sizeof(double);
    } 
    break;
    case MYSQL_TYPE_FLOAT:
    {
      float val= (float)my_atod(buffer, buffer + len, &error);
      *r_param->error= error > 0; /* no need to check for truncation */
      float4store(r_param->buffer, val);
      r_param->buffer_length= sizeof(float);
    } 
    break;
    case MYSQL_TYPE_TIME:
    case MYSQL_TYPE_DATE:
    case MYSQL_TYPE_DATETIME:
    case MYSQL_TYPE_TIMESTAMP:
    {
      MYSQL_TIME *tm= (MYSQL_TIME *)r_param->buffer;
      str_to_TIME(buffer, len, tm);
      break;
    }
    break;
    case MYSQL_TYPE_TINY_BLOB:
    case MYSQL_TYPE_MEDIUM_BLOB:
    case MYSQL_TYPE_LONG_BLOB:
    case MYSQL_TYPE_BLOB:
    case MYSQL_TYPE_DECIMAL:
    case MYSQL_TYPE_NEWDECIMAL:
    default:
    {
      char *start= buffer + r_param->offset; /* stmt_fetch_column sets offset */
      char *end= buffer + len;
      size_t copylen= 0;

      if (start < end)
      {
        copylen= end - start;
        if (r_param->buffer_length)
          memcpy(r_param->buffer, start, MIN(copylen, r_param->buffer_length));
      }
      if (copylen < r_param->buffer_length)
        ((char *)r_param->buffer)[copylen]= '\0';
      *r_param->error= (copylen > r_param->buffer_length);

      *r_param->length= (ulong)len; 
    }
    break;
  }
}
示例#3
0
uint sp_make_key(register MI_INFO *info, uint keynr, uchar *key,
		 const uchar *record, my_off_t filepos)
{
  HA_KEYSEG *keyseg;
  MI_KEYDEF *keyinfo = &info->s->keyinfo[keynr];
  uint len = 0;
  uchar *pos;
  uint dlen;
  uchar *dptr;
  double mbr[SPDIMS * 2];
  uint i;
  
  keyseg = &keyinfo->seg[-1];
  pos = (uchar*)record + keyseg->start;
  
  dlen = _mi_calc_blob_length(keyseg->bit_start, pos);
  memcpy(&dptr, pos + keyseg->bit_start, sizeof(char*));
  if (!dptr)
  {
    my_errno= HA_ERR_NULL_IN_SPATIAL;
    return 0;
  }
  sp_mbr_from_wkb(dptr + 4, dlen - 4, SPDIMS, mbr);	/* SRID */
  
  for (i = 0, keyseg = keyinfo->seg; keyseg->type; keyseg++, i++)
  {
    uint length = keyseg->length, start= keyseg->start;
    double val;

    DBUG_ASSERT(length == sizeof(double));
    DBUG_ASSERT(!(start % sizeof(double)));
    DBUG_ASSERT(start < sizeof(mbr));
    DBUG_ASSERT(keyseg->type == HA_KEYTYPE_DOUBLE);
    
    val= mbr[start / sizeof (double)];
#ifdef HAVE_ISNAN
    if (isnan(val))
    {
      bzero(key, length);
      key+= length;
      len+= length;
      continue;
    }
#endif

    if (keyseg->flag & HA_SWAP_KEY)
    {
      uchar buf[sizeof(double)];

      float8store(buf, val);
      pos= &buf[length];
      while (pos > buf)
        *key++ = *--pos;
    }
    else
    {
      float8store((uchar *)key, val);
      key += length;
    }
    len+= length;
  }
  _mi_dpointer(info, key, filepos);
  return len;
}
示例#4
0
/**************************************************

   read data in binary type 

**************************************************/ 
int mysac_encode_value(MYSAC_BIND *val, char *out, int len) {
	/*
	int j;
	int i;
	char nul;
	unsigned long len;
	int tmp_len;
	char *wh;
	char _null_ptr[16];
	char *null_ptr;
	unsigned char bit;
	*/
	int l;
//	int data_len;
	struct timeval *tv;
	struct tm *tm;
	unsigned int v;
	char sign;

	switch (val->type) {
	
	/* read null */
	case MYSQL_TYPE_NULL:
		l = 0;
		break;
	
	/* read blob */
	case MYSQL_TYPE_TINY_BLOB:
	case MYSQL_TYPE_MEDIUM_BLOB:
	case MYSQL_TYPE_LONG_BLOB:
	case MYSQL_TYPE_BLOB:
	/* decimal ? maybe for very big num ... crypto key ? */
	case MYSQL_TYPE_DECIMAL:
	case MYSQL_TYPE_NEWDECIMAL:
	/* .... */
	case MYSQL_TYPE_BIT:
	/* read text */
	case MYSQL_TYPE_STRING:
	case MYSQL_TYPE_VAR_STRING:
	case MYSQL_TYPE_VARCHAR:
	/* read date */
	case MYSQL_TYPE_NEWDATE:

		l = set_my_lcb(val->value_len, 0, out, len);
		if (l < 0)
			return -1;

		len -= l;

		if (len < val->value_len)
			return -1;

		memcpy(&out[l], val->value, val->value_len);
		l += val->value_len;
		break;
	
	case MYSQL_TYPE_TINY:
		if (len < 1)
			return -1;
		l = 1;
		out[0] = *(int *)val->value;
		break;
	
	case MYSQL_TYPE_SHORT:
		if (len < 2)
			return -1;
		l = 2;
		to_my_2(*(int *)val->value, out);
		break;
	
	case MYSQL_TYPE_INT24:
	case MYSQL_TYPE_LONG:
		if (len < 4)
			return -1;
		l = 4;
		to_my_4(*(int *)val->value, out);
		break;
	
	case MYSQL_TYPE_LONGLONG:
		if (len < 8)
			return -1;
		l = 8;
		to_my_8(*(long long int *)val->value, out);
		break;
	
	case MYSQL_TYPE_FLOAT:
		if (len < 4)
			return -1;
		l = 4;
		float4store((*(long *)val->value), out);
		break;
	
	case MYSQL_TYPE_DOUBLE:
		if (len < 8)
			return -1;
		l = 8;
		float8store(*(long *)val->value, out);
		break;
	
	/* libmysql/libmysql.c:3370
	 * static void read_binary_time(MYSQL_TIME *tm, uchar **pos) 
	 *
	 * n*lcb 4*j 1*h 1*m 1*s 1*sig 4*usec soit 12 bytes
	 */
	case MYSQL_TYPE_TIME:

		l = set_my_lcb(12, 0, out, len);
		if (l < 0)
			return -1;

		len -= l;

		if (len < 12)
			return -1;

		tv = (struct timeval *)val->value;
		if (tv->tv_sec < 0) {
			tv->tv_sec = - tv->tv_sec;
			sign = 1;
		}
		else
			sign = 0;

		/* nb days */
		to_my_4(tv->tv_sec / 86400, &out[l]);
		l += 4;

		/* remainder in secs */
		v = tv->tv_sec % 86400;

		/* nb hours */
		out[l] = v / 3600;
		l++;

		/* remainder in secs */
		v = v % 3600;

		/* nb mins */
		out[l] = v / 60;
		l++;

		/* secs */
		out[l] = v % 60;
		l++;

		/* signe */
		out[l] = sign;
		l++;

		/* u secs */
		to_my_4(tv->tv_usec, &out[l]);
		l += 4;

		break;
	
	case MYSQL_TYPE_YEAR:
		if (len < 2)
			return -1;

		tm = (struct tm *)val->value;
		to_my_2(tm->tm_year + 1900, out);
		l = 2;
		break;
	
	/* libmysql/libmysql.c:3400
	 * static void read_binary_datetime(MYSQL_TIME *tm, uchar **pos) 
	 *
	 * 1*lcb 2*year 1*mon 1*day 1*hour 1*min 1*sec
	 */
	case MYSQL_TYPE_TIMESTAMP:
	case MYSQL_TYPE_DATETIME:
		
		l = set_my_lcb(7, 0, out, len);
		if (l < 0)
			return -1;

		len -= l;

		if (len < 7)
			return -1;

		tm = (struct tm *)val->value;

		to_my_2(tm->tm_year + 1900, &out[l]);
		l += 2;

		out[l] = tm->tm_mon + 1;
		l++;

		out[l] = tm->tm_mday;
		l++;

		out[l] = tm->tm_hour;
		l++;

		out[l] = tm->tm_min;
		l++;

		out[l] = tm->tm_sec;
		l++;

		break;
	
	/* libmysql/libmysql.c:3430
	 * static void read_binary_date(MYSQL_TIME *tm, uchar **pos)
	 *
	 * 1*lcb 2*year 1*mon 1*day
	 */
	case MYSQL_TYPE_DATE:
		
		l = set_my_lcb(4, 0, out, len);
		if (l < 0)
			return -1;

		len -= l;

		if (len < 4)
			return -1;

		tm = (struct tm *)val->value;

		to_my_2(tm->tm_year + 1900, &out[l]);
		l += 2;

		out[l] = tm->tm_mon + 1;
		l++;

		out[l] = tm->tm_mday;
		l++;

		break;
	
	case MYSQL_TYPE_ENUM:
	case MYSQL_TYPE_SET:
	case MYSQL_TYPE_GEOMETRY:
		/* TODO: a faire */
		break;
	}

	return l;
}
示例#5
0
/* {{{ 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)
{
	unsigned int i;
	for (i = 0; i < stmt->param_count; i++) {
		zval *data, *parameter = &stmt->param_bind[i].zv;

		ZVAL_DEREF(parameter);
		data = (copies && !Z_ISUNDEF(copies[i]))? &copies[i]: parameter;
		/* Handle long data */
		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);
					float8store(*p, Z_DVAL_P(data));
					(*p) += 8;
					break;
				case MYSQL_TYPE_LONGLONG:
					if (Z_TYPE_P(data) == IS_STRING) {
						goto send_string;
					}
					/* data has alreade been converted to long */
					int8store(*p, Z_LVAL_P(data));
					(*p) += 8;
					break;
				case MYSQL_TYPE_LONG:
					if (Z_TYPE_P(data) == IS_STRING) {
						goto send_string;
					}
					/* data has alreade been converted to long */
					int4store(*p, Z_LVAL_P(data));
					(*p) += 4;
					break;
				case MYSQL_TYPE_LONG_BLOB:
					if (stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED) {
						stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
					} else {
						/* send_long_data() not called, send empty string */
						*p = php_mysqlnd_net_store_length(*p, 0);
					}
					break;
				case MYSQL_TYPE_VAR_STRING:
send_string:
					{
						size_t len = Z_STRLEN_P(data);
						/* to is after p. The latter hasn't been moved */
						*p = php_mysqlnd_net_store_length(*p, len);
						memcpy(*p, Z_STRVAL_P(data), len);
						(*p) += len;
					}
					break;
				default:
					/* Won't happen, but set to NULL */
					(buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7));
					break;
			}
		}
	}
}
示例#6
0
/* {{{ 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, unsigned int null_byte_offset TSRMLS_DC)
{
	MYSQLND_STMT_DATA * stmt = s->data;
	unsigned int i = 0;
	zend_uchar * provided_buffer = *buf;
	size_t left = (*buf_len - (*p - *buf));
	size_t data_size = 0;
	zval **copies = NULL;/* if there are different types */
	enum_func_status ret = FAIL;
	int resend_types_next_time = 0;

	DBG_ENTER("mysqlnd_stmt_execute_store_params");

/* 1. Store type information */
	/*
	  check if need to send the types even if stmt->send_types_to_server is 0. This is because
	  if we send "i" (42) then the type will be int and the server will expect int. However, if next
	  time we try to send > LONG_MAX, the conversion to string will send a string and the server
	  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.
	*/
	for (i = 0; i < stmt->param_count; i++) {
		if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_NULL &&
			(stmt->param_bind[i].type == MYSQL_TYPE_LONG || stmt->param_bind[i].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, stmt->param_bind[i].zv, stmt->param_count, i TSRMLS_CC))
			{
				SET_OOM_ERROR(stmt->error_info);
				goto end;
			}
			/*
			  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;
				convert_to_double_ex(&tmp_data);
				if (Z_DVAL_P(tmp_data) > LONG_MAX || Z_DVAL_P(tmp_data) < LONG_MIN) {
					stmt->send_types_to_server = resend_types_next_time = 1;
				}
			}
		}
	}

	int1store(*p, stmt->send_types_to_server); 
	(*p)++;

	if (stmt->send_types_to_server) {
		/* 2 bytes per type, and leave 20 bytes for future use */
		if (left < ((stmt->param_count * 2) + 20)) {
			unsigned int offset = *p - *buf;
			zend_uchar *tmp_buf;
			*buf_len = offset + stmt->param_count * 2 + 20;
			tmp_buf = mnd_emalloc(*buf_len);
			if (!tmp_buf) {
				SET_OOM_ERROR(stmt->error_info);
				goto end;
			}
			memcpy(tmp_buf, *buf, offset);
			*buf = tmp_buf;

			/* Update our pos pointer */
			*p = *buf + offset;
		}
		for (i = 0; i < stmt->param_count; i++) {
			short current_type = stmt->param_bind[i].type;
			/* our types are not unsigned */
#if SIZEOF_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)) {
				/*
				  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;

					convert_to_double_ex(&tmp_data);
					if (Z_DVAL_P(tmp_data) > LONG_MAX || Z_DVAL_P(tmp_data) < LONG_MIN) {
						convert_to_string_ex(&tmp_data);
						current_type = MYSQL_TYPE_VAR_STRING;
						/*
						  don't change stmt->param_bind[i].type to MYSQL_TYPE_VAR_STRING
						  we force convert_to_long_ex in all cases, thus the type will be right in the next switch.
						  if the type is however not long, then we will do a goto in the next switch.
						  We want to preserve the original bind type given by the user. Thus, we do these hacks.
						*/
					} else {
						convert_to_long_ex(&tmp_data);
					}
				}
			}
			int2store(*p, current_type);
			*p+= 2;
		}
	}
	stmt->send_types_to_server = resend_types_next_time;

/* 2. Store data */
	/* 2.1 Calculate how much space we need */
	for (i = 0; i < stmt->param_count; i++) {
		unsigned int j;
		zval *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)) {
			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 || !copies[i]) {
					if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) {
						SET_OOM_ERROR(stmt->error_info);
						goto end;
					}
				}
				break; 
			}
		}

		switch (stmt->param_bind[i].type) {
			case MYSQL_TYPE_DOUBLE:
				data_size += 8;
				if (Z_TYPE_P(the_var) != IS_DOUBLE) {
					if (!copies || !copies[i]) {
						if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) {
							SET_OOM_ERROR(stmt->error_info);
							goto end;
						}
					}
				}
				break;
			case MYSQL_TYPE_LONGLONG:
				{
					zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv;
					if (Z_TYPE_P(tmp_data) == IS_STRING) {
						goto use_string;
					}
					convert_to_long_ex(&tmp_data);
				}
				data_size += 8;
				break;
			case MYSQL_TYPE_LONG:
				{
					zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv;
					if (Z_TYPE_P(tmp_data) == IS_STRING) {
						goto use_string;
					}
					convert_to_long_ex(&tmp_data);
				}
				data_size += 4;
				break;
			case MYSQL_TYPE_LONG_BLOB:
				if (!(stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED)) {
					/*
					  User hasn't sent anything, we will send empty string.
					  Empty string has length of 0, encoded in 1 byte. No real
					  data will follows after it.
					*/
					data_size++;
				}
				break;
			case MYSQL_TYPE_VAR_STRING:
use_string:
				data_size += 8; /* max 8 bytes for size */
#if MYSQLND_UNICODE
				if (Z_TYPE_P(the_var) != IS_STRING || Z_TYPE_P(the_var) == IS_UNICODE)
#else
				if (Z_TYPE_P(the_var) != IS_STRING)
#endif
				{
					if (!copies || !copies[i]) {
						if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) {
							SET_OOM_ERROR(stmt->error_info);
							goto end;
						}
					}
					the_var = copies[i];
#if MYSQLND_UNICODE
					if (Z_TYPE_P(the_var) == IS_UNICODE) {
						zval_unicode_to_string_ex(the_var, UG(utf8_conv) TSRMLS_CC);
					}
#endif
				}
				convert_to_string_ex(&the_var);
				data_size += Z_STRLEN_P(the_var);
				break;
		}
	}

	/* 2.2 Enlarge the buffer, if needed */
	left = (*buf_len - (*p - *buf));
	if (left < data_size) {
		unsigned int offset = *p - *buf;
		zend_uchar *tmp_buf;
		*buf_len = offset + data_size + 10; /* Allocate + 10 for safety */
		tmp_buf = mnd_emalloc(*buf_len);
		if (!tmp_buf) {
			SET_OOM_ERROR(stmt->error_info);
			goto end;
		}
		memcpy(tmp_buf, *buf, offset);
		/*
		  When too many columns the buffer provided to the function might not be sufficient.
		  In this case new buffer has been allocated above. When we allocate a buffer and then
		  allocate a bigger one here, we should free the first one.
		*/
		if (*buf != provided_buffer) {
			mnd_efree(*buf);
		}
		*buf = tmp_buf;
		/* Update our pos pointer */
		*p = *buf + offset;
	}

	/* 2.3 Store the actual data */
	for (i = 0; i < stmt->param_count; i++) {
		zval *data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv;
		/* Handle long data */
		if (stmt->param_bind[i].zv && 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);
					float8store(*p, Z_DVAL_P(data));
					(*p) += 8;
					break;
				case MYSQL_TYPE_LONGLONG:
					if (Z_TYPE_P(data) == IS_STRING) {
						goto send_string;
					}
					/* data has alreade been converted to long */
					int8store(*p, Z_LVAL_P(data));
					(*p) += 8;
					break;
				case MYSQL_TYPE_LONG:
					if (Z_TYPE_P(data) == IS_STRING) {
						goto send_string;
					}
					/* data has alreade been converted to long */
					int4store(*p, Z_LVAL_P(data));
					(*p) += 4;
					break;
				case MYSQL_TYPE_LONG_BLOB:
					if (stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED) {
						stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
					} else {
						/* send_long_data() not called, send empty string */
						*p = php_mysqlnd_net_store_length(*p, 0);
					}
					break;
				case MYSQL_TYPE_VAR_STRING:
send_string:
					{
						unsigned int len = Z_STRLEN_P(data);
						/* to is after p. The latter hasn't been moved */
						*p = php_mysqlnd_net_store_length(*p, len);
						memcpy(*p, Z_STRVAL_P(data), len);
						(*p) += len;
					}
					break;
				default:
					/* Won't happen, but set to NULL */
					(*buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7));
					break;
			}
		}
	}
	ret = PASS;
end:
	if (copies) {
		for (i = 0; i < stmt->param_count; i++) {
			if (copies[i]) {
				zval_ptr_dtor(&copies[i]);
			}
		}
		mnd_efree(copies);
	}

	DBG_INF_FMT("ret=%s", ret == PASS? "PASS":"******");
	DBG_RETURN(ret);
}