xref: /PHP-5.6/ext/mysqlnd/mysqlnd_ps_codec.c (revision 49493a2d)
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 5                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 2006-2016 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.php.net/license/3_01.txt                                  |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Authors: Andrey Hristov <andrey@mysql.com>                           |
16   |          Ulf Wendel <uwendel@mysql.com>                              |
17   |          Georg Richter <georg@mysql.com>                             |
18   +----------------------------------------------------------------------+
19 */
20 
21 /* $Id$ */
22 #include "php.h"
23 #include "mysqlnd.h"
24 #include "mysqlnd_wireprotocol.h"
25 #include "mysqlnd_priv.h"
26 #include "mysqlnd_debug.h"
27 #include "ext/mysqlnd/mysql_float_to_double.h"
28 
29 #define MYSQLND_SILENT
30 
31 
32 enum mysqlnd_timestamp_type
33 {
34   MYSQLND_TIMESTAMP_NONE= -2,
35   MYSQLND_TIMESTAMP_ERROR= -1,
36   MYSQLND_TIMESTAMP_DATE= 0,
37   MYSQLND_TIMESTAMP_DATETIME= 1,
38   MYSQLND_TIMESTAMP_TIME= 2
39 };
40 
41 
42 struct st_mysqlnd_time
43 {
44   unsigned int  year, month, day, hour, minute, second;
45   unsigned long second_part;
46   zend_bool     neg;
47   enum mysqlnd_timestamp_type time_type;
48 };
49 
50 
51 struct st_mysqlnd_perm_bind mysqlnd_ps_fetch_functions[MYSQL_TYPE_LAST + 1];
52 
53 #define MYSQLND_PS_SKIP_RESULT_W_LEN	-1
54 #define MYSQLND_PS_SKIP_RESULT_STR		-2
55 
56 /* {{{ ps_fetch_from_1_to_8_bytes */
57 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)58 ps_fetch_from_1_to_8_bytes(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len,
59 						   zend_uchar ** row, unsigned int byte_count TSRMLS_DC)
60 {
61 	char tmp[22];
62 	size_t tmp_len = 0;
63 	zend_bool is_bit = field->type == MYSQL_TYPE_BIT;
64 	DBG_ENTER("ps_fetch_from_1_to_8_bytes");
65 	DBG_INF_FMT("zv=%p byte_count=%u", zv, byte_count);
66 	if (field->flags & UNSIGNED_FLAG) {
67 		uint64_t uval = 0;
68 
69 		switch (byte_count) {
70 			case 8:uval = is_bit? (uint64_t) bit_uint8korr(*row):(uint64_t) uint8korr(*row);break;
71 			case 7:uval = bit_uint7korr(*row);break;
72 			case 6:uval = bit_uint6korr(*row);break;
73 			case 5:uval = bit_uint5korr(*row);break;
74 			case 4:uval = is_bit? (uint64_t) bit_uint4korr(*row):(uint64_t) uint4korr(*row);break;
75 			case 3:uval = is_bit? (uint64_t) bit_uint3korr(*row):(uint64_t) uint3korr(*row);break;
76 			case 2:uval = is_bit? (uint64_t) bit_uint2korr(*row):(uint64_t) uint2korr(*row);break;
77 			case 1:uval = (uint64_t) uint1korr(*row);break;
78 		}
79 
80 #if SIZEOF_LONG==4
81 		if (uval > INT_MAX) {
82 			DBG_INF("stringify");
83 			tmp_len = sprintf((char *)&tmp, MYSQLND_LLU_SPEC, uval);
84 		} else
85 #endif /* #if SIZEOF_LONG==4 */
86 		{
87 			if (byte_count < 8 || uval <= L64(9223372036854775807)) {
88 				ZVAL_LONG(zv, (long) uval); /* the cast is safe, we are in the range */
89 			} else {
90 				DBG_INF("stringify");
91 				tmp_len = sprintf((char *)&tmp, MYSQLND_LLU_SPEC, uval);
92 			}
93 		}
94 	} else {
95 		/* SIGNED */
96 		int64_t lval = 0;
97 		switch (byte_count) {
98 			case 8:lval = (int64_t) sint8korr(*row);break;
99 			/*
100 			  7, 6 and 5 are not possible.
101 			  BIT is only unsigned, thus only uint5|6|7 macroses exist
102 			*/
103 			case 4:lval = (int64_t) sint4korr(*row);break;
104 			case 3:lval = (int64_t) sint3korr(*row);break;
105 			case 2:lval = (int64_t) sint2korr(*row);break;
106 			case 1:lval = (int64_t) *(int8_t*)*row;break;
107 		}
108 
109 #if SIZEOF_LONG==4
110 		if ((L64(2147483647) < (int64_t) lval) || (L64(-2147483648) > (int64_t) lval)) {
111 			DBG_INF("stringify");
112 			tmp_len = sprintf((char *)&tmp, MYSQLND_LL_SPEC, lval);
113 		} else
114 #endif /* SIZEOF */
115 		{
116 			ZVAL_LONG(zv, (long) lval); /* the cast is safe, we are in the range */
117 		}
118 	}
119 
120 	if (tmp_len) {
121 		ZVAL_STRINGL(zv, tmp, tmp_len, 1);
122 	}
123 	(*row)+= byte_count;
124 	DBG_VOID_RETURN;
125 }
126 /* }}} */
127 
128 
129 /* {{{ ps_fetch_null */
130 static void
ps_fetch_null(zval * zv,const MYSQLND_FIELD * const field,unsigned int pack_len,zend_uchar ** row TSRMLS_DC)131 ps_fetch_null(zval *zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC)
132 {
133 	ZVAL_NULL(zv);
134 }
135 /* }}} */
136 
137 
138 /* {{{ ps_fetch_int8 */
139 static void
ps_fetch_int8(zval * zv,const MYSQLND_FIELD * const field,unsigned int pack_len,zend_uchar ** row TSRMLS_DC)140 ps_fetch_int8(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC)
141 {
142 	ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, 1 TSRMLS_CC);
143 }
144 /* }}} */
145 
146 
147 /* {{{ ps_fetch_int16 */
148 static void
ps_fetch_int16(zval * zv,const MYSQLND_FIELD * const field,unsigned int pack_len,zend_uchar ** row TSRMLS_DC)149 ps_fetch_int16(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC)
150 {
151 	ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, 2 TSRMLS_CC);
152 }
153 /* }}} */
154 
155 
156 /* {{{ ps_fetch_int32 */
157 static void
ps_fetch_int32(zval * zv,const MYSQLND_FIELD * const field,unsigned int pack_len,zend_uchar ** row TSRMLS_DC)158 ps_fetch_int32(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC)
159 {
160 	ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, 4 TSRMLS_CC);
161 }
162 /* }}} */
163 
164 
165 /* {{{ ps_fetch_int64 */
166 static void
ps_fetch_int64(zval * zv,const MYSQLND_FIELD * const field,unsigned int pack_len,zend_uchar ** row TSRMLS_DC)167 ps_fetch_int64(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC)
168 {
169 	ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, 8 TSRMLS_CC);
170 }
171 /* }}} */
172 
173 
174 /* {{{ ps_fetch_float */
175 static void
ps_fetch_float(zval * zv,const MYSQLND_FIELD * const field,unsigned int pack_len,zend_uchar ** row TSRMLS_DC)176 ps_fetch_float(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC)
177 {
178 	float fval;
179 	double dval;
180 	DBG_ENTER("ps_fetch_float");
181 	float4get(fval, *row);
182 	(*row)+= 4;
183 	DBG_INF_FMT("value=%f", fval);
184 
185 #ifndef NOT_FIXED_DEC
186 # define NOT_FIXED_DEC 31
187 #endif
188 
189 	dval = mysql_float_to_double(fval, (field->decimals >= NOT_FIXED_DEC) ? -1 : field->decimals);
190 
191 	ZVAL_DOUBLE(zv, dval);
192 	DBG_VOID_RETURN;
193 }
194 /* }}} */
195 
196 
197 /* {{{ ps_fetch_double */
198 static void
ps_fetch_double(zval * zv,const MYSQLND_FIELD * const field,unsigned int pack_len,zend_uchar ** row TSRMLS_DC)199 ps_fetch_double(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC)
200 {
201 	double value;
202 	DBG_ENTER("ps_fetch_double");
203 	float8get(value, *row);
204 	ZVAL_DOUBLE(zv, value);
205 	(*row)+= 8;
206 	DBG_INF_FMT("value=%f", value);
207 	DBG_VOID_RETURN;
208 }
209 /* }}} */
210 
211 
212 /* {{{ ps_fetch_time */
213 static void
ps_fetch_time(zval * zv,const MYSQLND_FIELD * const field,unsigned int pack_len,zend_uchar ** row TSRMLS_DC)214 ps_fetch_time(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC)
215 {
216 	struct st_mysqlnd_time t;
217 	unsigned long length; /* First byte encodes the length*/
218 	char * value;
219 	DBG_ENTER("ps_fetch_time");
220 
221 	if ((length = php_mysqlnd_net_field_length(row))) {
222 		zend_uchar * to= *row;
223 
224 		t.time_type = MYSQLND_TIMESTAMP_TIME;
225 		t.neg			= (zend_bool) to[0];
226 
227 		t.day			= (unsigned long) sint4korr(to+1);
228 		t.hour			= (unsigned int) to[5];
229 		t.minute		= (unsigned int) to[6];
230 		t.second		= (unsigned int) to[7];
231 		t.second_part	= (length > 8) ? (unsigned long) sint4korr(to+8) : 0;
232 		t.year			= t.month= 0;
233 		if (t.day) {
234 			/* Convert days to hours at once */
235 			t.hour += t.day*24;
236 			t.day	= 0;
237 		}
238 
239 		(*row) += length;
240 	} else {
241 		memset(&t, 0, sizeof(t));
242 		t.time_type = MYSQLND_TIMESTAMP_TIME;
243 	}
244 
245 	length = mnd_sprintf(&value, 0, "%s%02u:%02u:%02u", (t.neg ? "-" : ""), t.hour, t.minute, t.second);
246 
247 	DBG_INF_FMT("%s", value);
248 	ZVAL_STRINGL(zv, value, length, 1);
249 	mnd_sprintf_free(value);
250 	DBG_VOID_RETURN;
251 }
252 /* }}} */
253 
254 
255 /* {{{ ps_fetch_date */
256 static void
ps_fetch_date(zval * zv,const MYSQLND_FIELD * const field,unsigned int pack_len,zend_uchar ** row TSRMLS_DC)257 ps_fetch_date(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC)
258 {
259 	struct st_mysqlnd_time t = {0};
260 	unsigned long length; /* First byte encodes the length*/
261 	char * value;
262 	DBG_ENTER("ps_fetch_date");
263 
264 	if ((length = php_mysqlnd_net_field_length(row))) {
265 		zend_uchar *to= *row;
266 
267 		t.time_type= MYSQLND_TIMESTAMP_DATE;
268 		t.neg= 0;
269 
270 		t.second_part = t.hour = t.minute = t.second = 0;
271 
272 		t.year	= (unsigned int) sint2korr(to);
273 		t.month = (unsigned int) to[2];
274 		t.day	= (unsigned int) to[3];
275 
276 		(*row)+= length;
277 	} else {
278 		memset(&t, 0, sizeof(t));
279 		t.time_type = MYSQLND_TIMESTAMP_DATE;
280 	}
281 
282 	length = mnd_sprintf(&value, 0, "%04u-%02u-%02u", t.year, t.month, t.day);
283 
284 	DBG_INF_FMT("%s", value);
285 	ZVAL_STRINGL(zv, value, length, 1);
286 	mnd_sprintf_free(value);
287 	DBG_VOID_RETURN;
288 }
289 /* }}} */
290 
291 
292 /* {{{ ps_fetch_datetime */
293 static void
ps_fetch_datetime(zval * zv,const MYSQLND_FIELD * const field,unsigned int pack_len,zend_uchar ** row TSRMLS_DC)294 ps_fetch_datetime(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC)
295 {
296 	struct st_mysqlnd_time t;
297 	unsigned long length; /* First byte encodes the length*/
298 	char * value;
299 	DBG_ENTER("ps_fetch_datetime");
300 
301 	if ((length = php_mysqlnd_net_field_length(row))) {
302 		zend_uchar * to = *row;
303 
304 		t.time_type = MYSQLND_TIMESTAMP_DATETIME;
305 		t.neg	 = 0;
306 
307 		t.year	 = (unsigned int) sint2korr(to);
308 		t.month = (unsigned int) to[2];
309 		t.day	 = (unsigned int) to[3];
310 
311 		if (length > 4) {
312 			t.hour	 = (unsigned int) to[4];
313 			t.minute = (unsigned int) to[5];
314 			t.second = (unsigned int) to[6];
315 		} else {
316 			t.hour = t.minute = t.second= 0;
317 		}
318 		t.second_part = (length > 7) ? (unsigned long) sint4korr(to+7) : 0;
319 
320 		(*row)+= length;
321 	} else {
322 		memset(&t, 0, sizeof(t));
323 		t.time_type = MYSQLND_TIMESTAMP_DATETIME;
324 	}
325 
326 	length = mnd_sprintf(&value, 0, "%04u-%02u-%02u %02u:%02u:%02u", t.year, t.month, t.day, t.hour, t.minute, t.second);
327 
328 	DBG_INF_FMT("%s", value);
329 	ZVAL_STRINGL(zv, value, length, 1);
330 	mnd_sprintf_free(value);
331 	DBG_VOID_RETURN;
332 }
333 /* }}} */
334 
335 
336 /* {{{ ps_fetch_string */
337 static void
ps_fetch_string(zval * zv,const MYSQLND_FIELD * const field,unsigned int pack_len,zend_uchar ** row TSRMLS_DC)338 ps_fetch_string(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC)
339 {
340 	/*
341 	  For now just copy, before we make it possible
342 	  to write \0 to the row buffer
343 	*/
344 	const unsigned long length = php_mysqlnd_net_field_length(row);
345 	DBG_ENTER("ps_fetch_string");
346 	DBG_INF_FMT("len = %lu", length);
347 	DBG_INF("copying from the row buffer");
348 	ZVAL_STRINGL(zv, (char *)*row, length, 1);
349 
350 	(*row) += length;
351 	DBG_VOID_RETURN;
352 }
353 /* }}} */
354 
355 
356 /* {{{ ps_fetch_bit */
357 static void
ps_fetch_bit(zval * zv,const MYSQLND_FIELD * const field,unsigned int pack_len,zend_uchar ** row TSRMLS_DC)358 ps_fetch_bit(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_len, zend_uchar ** row TSRMLS_DC)
359 {
360 	unsigned long length = php_mysqlnd_net_field_length(row);
361 	ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, length TSRMLS_CC);
362 }
363 /* }}} */
364 
365 
366 /* {{{ _mysqlnd_init_ps_fetch_subsystem */
_mysqlnd_init_ps_fetch_subsystem()367 void _mysqlnd_init_ps_fetch_subsystem()
368 {
369 	memset(mysqlnd_ps_fetch_functions, 0, sizeof(mysqlnd_ps_fetch_functions));
370 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].func		= ps_fetch_null;
371 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].pack_len	= 0;
372 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].php_type	= IS_NULL;
373 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].can_ret_as_str_in_uni	= TRUE;
374 
375 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].func		= ps_fetch_int8;
376 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].pack_len	= 1;
377 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].php_type	= IS_LONG;
378 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].can_ret_as_str_in_uni	= TRUE;
379 
380 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].func		= ps_fetch_int16;
381 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].pack_len	= 2;
382 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].php_type	= IS_LONG;
383 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].can_ret_as_str_in_uni	= TRUE;
384 
385 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].func		= ps_fetch_int16;
386 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].pack_len	= 2;
387 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].php_type	= IS_LONG;
388 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].can_ret_as_str_in_uni	= TRUE;
389 
390 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].func		= ps_fetch_int32;
391 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].pack_len	= 4;
392 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].php_type	= IS_LONG;
393 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].can_ret_as_str_in_uni	= TRUE;
394 
395 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].func		= ps_fetch_int32;
396 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].pack_len	= 4;
397 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].php_type	= IS_LONG;
398 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].can_ret_as_str_in_uni	= TRUE;
399 
400 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].func	= ps_fetch_int64;
401 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].pack_len= 8;
402 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].php_type= IS_LONG;
403 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].can_ret_as_str_in_uni	= TRUE;
404 
405 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].func		= ps_fetch_float;
406 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].pack_len	= 4;
407 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].php_type	= IS_DOUBLE;
408 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].can_ret_as_str_in_uni	= TRUE;
409 
410 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].func		= ps_fetch_double;
411 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].pack_len	= 8;
412 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].php_type	= IS_DOUBLE;
413 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].can_ret_as_str_in_uni	= TRUE;
414 
415 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].func		= ps_fetch_time;
416 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].pack_len	= MYSQLND_PS_SKIP_RESULT_W_LEN;
417 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].php_type	= IS_STRING;
418 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].can_ret_as_str_in_uni	= TRUE;
419 
420 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].func		= ps_fetch_date;
421 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].pack_len	= MYSQLND_PS_SKIP_RESULT_W_LEN;
422 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].php_type	= IS_STRING;
423 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].can_ret_as_str_in_uni	= TRUE;
424 
425 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].func		= ps_fetch_string;
426 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].pack_len	= MYSQLND_PS_SKIP_RESULT_W_LEN;
427 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].php_type	= IS_STRING;
428 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].can_ret_as_str_in_uni	= TRUE;
429 
430 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].func	= ps_fetch_datetime;
431 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].pack_len= MYSQLND_PS_SKIP_RESULT_W_LEN;
432 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].php_type= IS_STRING;
433 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].can_ret_as_str_in_uni	= TRUE;
434 
435 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].func	= ps_fetch_datetime;
436 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].pack_len= MYSQLND_PS_SKIP_RESULT_W_LEN;
437 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].php_type= IS_STRING;
438 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].can_ret_as_str_in_uni	= TRUE;
439 
440 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_JSON].func	= ps_fetch_string;
441 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_JSON].pack_len= MYSQLND_PS_SKIP_RESULT_STR;
442 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_JSON].php_type = IS_STRING;
443 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_JSON].is_possibly_blob = TRUE;
444 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_JSON].can_ret_as_str_in_uni	= TRUE;
445 
446 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].func	= ps_fetch_string;
447 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].pack_len= MYSQLND_PS_SKIP_RESULT_STR;
448 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].php_type = IS_STRING;
449 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].is_possibly_blob = TRUE;
450 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].can_ret_as_str_in_uni	= TRUE;
451 
452 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].func		= ps_fetch_string;
453 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].pack_len	= MYSQLND_PS_SKIP_RESULT_STR;
454 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].php_type	= IS_STRING;
455 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].is_possibly_blob = TRUE;
456 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].can_ret_as_str_in_uni	= TRUE;
457 
458 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].func		= ps_fetch_string;
459 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].pack_len	= MYSQLND_PS_SKIP_RESULT_STR;
460 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].php_type	= IS_STRING;
461 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].is_possibly_blob = TRUE;
462 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].can_ret_as_str_in_uni	= TRUE;
463 
464 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].func		= ps_fetch_string;
465 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].pack_len	= MYSQLND_PS_SKIP_RESULT_STR;
466 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].php_type	= IS_STRING;
467 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].is_possibly_blob = TRUE;
468 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].can_ret_as_str_in_uni 	= TRUE;
469 
470 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].func		= ps_fetch_bit;
471 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].pack_len	= 8;
472 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].php_type	= IS_LONG;
473 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].can_ret_as_str_in_uni = TRUE;
474 
475 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].func		= ps_fetch_string;
476 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].pack_len	= MYSQLND_PS_SKIP_RESULT_STR;
477 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].php_type = IS_STRING;
478 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].is_possibly_blob = TRUE;
479 
480 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].func		= ps_fetch_string;
481 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].pack_len	= MYSQLND_PS_SKIP_RESULT_STR;
482 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].php_type	= IS_STRING;
483 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].is_possibly_blob = TRUE;
484 
485 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].func			= ps_fetch_string;
486 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].pack_len		= MYSQLND_PS_SKIP_RESULT_STR;
487 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].php_type	= IS_STRING;
488 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].is_possibly_blob = TRUE;
489 
490 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].func		= ps_fetch_string;
491 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].pack_len	= MYSQLND_PS_SKIP_RESULT_STR;
492 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].php_type	= IS_STRING;
493 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].can_ret_as_str_in_uni	= TRUE;
494 
495 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].func		= ps_fetch_string;
496 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].pack_len	= MYSQLND_PS_SKIP_RESULT_STR;
497 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].php_type	= IS_STRING;
498 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].can_ret_as_str_in_uni	= TRUE;
499 
500 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_ENUM].func		= ps_fetch_string;
501 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_ENUM].pack_len	= MYSQLND_PS_SKIP_RESULT_STR;
502 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_ENUM].php_type	= IS_STRING;
503 
504 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_SET].func			= ps_fetch_string;
505 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_SET].pack_len		= MYSQLND_PS_SKIP_RESULT_STR;
506 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_SET].php_type		= IS_STRING;
507 
508 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].func	= ps_fetch_string;
509 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].pack_len= MYSQLND_PS_SKIP_RESULT_STR;
510 	mysqlnd_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].php_type= IS_STRING;
511 }
512 /* }}} */
513 
514 
515 /* {{{ mysqlnd_stmt_copy_it */
516 static enum_func_status
mysqlnd_stmt_copy_it(zval *** copies,zval * original,unsigned int param_count,unsigned int current TSRMLS_DC)517 mysqlnd_stmt_copy_it(zval *** copies, zval * original, unsigned int param_count, unsigned int current TSRMLS_DC)
518 {
519 	if (!*copies) {
520 		*copies = mnd_ecalloc(param_count, sizeof(zval *));
521 	}
522 	if (*copies) {
523 		MAKE_STD_ZVAL((*copies)[current]);
524 		*(*copies)[current] = *original;
525 		Z_SET_REFCOUNT_P((*copies)[current], 1);
526 		zval_copy_ctor((*copies)[current]);
527 		return PASS;
528 	}
529 	return FAIL;
530 }
531 /* }}} */
532 
533 
534 /* {{{ mysqlnd_stmt_free_copies */
535 static void
mysqlnd_stmt_free_copies(MYSQLND_STMT_DATA * stmt,zval ** copies TSRMLS_DC)536 mysqlnd_stmt_free_copies(MYSQLND_STMT_DATA * stmt, zval ** copies TSRMLS_DC)
537 {
538 	if (copies) {
539 		unsigned int i;
540 		for (i = 0; i < stmt->param_count; i++) {
541 			if (copies[i]) {
542 				zval_ptr_dtor(&copies[i]);
543 			}
544 		}
545 		mnd_efree(copies);
546 	}
547 }
548 /* }}} */
549 
550 
551 /* {{{ mysqlnd_stmt_execute_check_n_enlarge_buffer */
552 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)553 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)
554 {
555 	const size_t overalloc = 5;
556 	size_t left = (*buf_len - (*p - *buf));
557 
558 	if (left < (needed_bytes + overalloc)) {
559 		size_t offset = *p - *buf;
560 		zend_uchar *tmp_buf;
561 		*buf_len = offset + needed_bytes + overalloc;
562 		tmp_buf = mnd_emalloc(*buf_len);
563 		if (!tmp_buf) {
564 			return FAIL;
565 		}
566 		memcpy(tmp_buf, *buf, offset);
567 		if (*buf != provided_buffer) {
568 			mnd_efree(*buf);
569 		}
570 		*buf = tmp_buf;
571 		/* Update our pos pointer */
572 		*p = *buf + offset;
573 	}
574 	return PASS;
575 }
576 /* }}} */
577 
578 
579 /* {{{ mysqlnd_stmt_execute_prepare_param_types */
580 static enum_func_status
mysqlnd_stmt_execute_prepare_param_types(MYSQLND_STMT_DATA * stmt,zval *** copies_param,int * resend_types_next_time TSRMLS_DC)581 mysqlnd_stmt_execute_prepare_param_types(MYSQLND_STMT_DATA * stmt, zval *** copies_param, int * resend_types_next_time TSRMLS_DC)
582 {
583 	unsigned int i;
584 	DBG_ENTER("mysqlnd_stmt_execute_prepare_param_types");
585 	for (i = 0; i < stmt->param_count; i++) {
586 		short current_type = stmt->param_bind[i].type;
587 
588 		if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_NULL && (current_type == MYSQL_TYPE_LONG || current_type == MYSQL_TYPE_LONGLONG)) {
589 			zval ** copies;
590 			/* always copy the var, because we do many conversions */
591 			if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG &&
592 				PASS != mysqlnd_stmt_copy_it(copies_param, stmt->param_bind[i].zv, stmt->param_count, i TSRMLS_CC))
593 			{
594 				SET_OOM_ERROR(*stmt->error_info);
595 				goto end;
596 			}
597 			copies = *copies_param;
598 			/*
599 			  if it doesn't fit in a long send it as a string.
600 			  Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX
601 			*/
602 			if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG) {
603 				zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv;
604 				/*
605 				  Because converting to double and back to long can lead
606 				  to losing precision we need second variable. Conversion to double is to see if
607 				  value is too big for a long. As said, precision could be lost.
608 				*/
609 				zval *tmp_data_copy;
610 				MAKE_STD_ZVAL(tmp_data_copy);
611 				*tmp_data_copy = *tmp_data;
612 				Z_SET_REFCOUNT_P(tmp_data_copy, 1);
613 				zval_copy_ctor(tmp_data_copy);
614 				convert_to_double_ex(&tmp_data_copy);
615 
616 				/*
617 				  if it doesn't fit in a long send it as a string.
618 				  Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX
619 				  We do transformation here, which will be used later when sending types. The code later relies on this.
620 				*/
621 				if (Z_DVAL_P(tmp_data_copy) > LONG_MAX || Z_DVAL_P(tmp_data_copy) < LONG_MIN) {
622 					stmt->send_types_to_server = *resend_types_next_time = 1;
623 					convert_to_string_ex(&tmp_data);
624 				} else {
625 					convert_to_long_ex(&tmp_data);
626 				}
627 
628 				zval_ptr_dtor(&tmp_data_copy);
629 			}
630 		}
631 	}
632 	DBG_RETURN(PASS);
633 end:
634 	DBG_RETURN(FAIL);
635 }
636 /* }}} */
637 
638 
639 /* {{{ mysqlnd_stmt_execute_store_types */
640 static void
mysqlnd_stmt_execute_store_types(MYSQLND_STMT_DATA * stmt,zval ** copies,zend_uchar ** p)641 mysqlnd_stmt_execute_store_types(MYSQLND_STMT_DATA * stmt, zval ** copies, zend_uchar ** p)
642 {
643 	unsigned int i;
644 	for (i = 0; i < stmt->param_count; i++) {
645 		short current_type = stmt->param_bind[i].type;
646 		/* our types are not unsigned */
647 #if SIZEOF_LONG==8
648 		if (current_type == MYSQL_TYPE_LONG) {
649 			current_type = MYSQL_TYPE_LONGLONG;
650 		}
651 #endif
652 		if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_NULL && (current_type == MYSQL_TYPE_LONG || current_type == MYSQL_TYPE_LONGLONG)) {
653 			/*
654 			  if it doesn't fit in a long send it as a string.
655 			  Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX
656 			*/
657 			if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG) {
658 				const zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv;
659 				/*
660 				  In case of IS_LONG we do nothing, it is ok, in case of string, we just need to set current_type.
661 				  The actual transformation has been performed several dozens line above.
662 				*/
663 				if (Z_TYPE_P(tmp_data) == IS_STRING) {
664 					current_type = MYSQL_TYPE_VAR_STRING;
665 					/*
666 					  don't change stmt->param_bind[i].type to MYSQL_TYPE_VAR_STRING
667 					  we force convert_to_long_ex in all cases, thus the type will be right in the next switch.
668 					  if the type is however not long, then we will do a goto in the next switch.
669 					  We want to preserve the original bind type given by the user. Thus, we do these hacks.
670 					*/
671 				}
672 			}
673 		}
674 		int2store(*p, current_type);
675 		*p+= 2;
676 	}
677 }
678 /* }}} */
679 
680 
681 /* {{{ mysqlnd_stmt_execute_calculate_param_values_size */
682 static enum_func_status
mysqlnd_stmt_execute_calculate_param_values_size(MYSQLND_STMT_DATA * stmt,zval *** copies_param,size_t * data_size TSRMLS_DC)683 mysqlnd_stmt_execute_calculate_param_values_size(MYSQLND_STMT_DATA * stmt, zval *** copies_param, size_t * data_size TSRMLS_DC)
684 {
685 	unsigned int i;
686 	DBG_ENTER("mysqlnd_stmt_execute_calculate_param_values_size");
687 	for (i = 0; i < stmt->param_count; i++) {
688 		unsigned short is_longlong = 0;
689 		unsigned int j;
690 		zval *the_var = stmt->param_bind[i].zv;
691 
692 		if (!the_var || (stmt->param_bind[i].type != MYSQL_TYPE_LONG_BLOB && Z_TYPE_P(the_var) == IS_NULL)) {
693 			continue;
694 		}
695 		for (j = i + 1; j < stmt->param_count; j++) {
696 			if (stmt->param_bind[j].zv == the_var) {
697 				/* Double binding of the same zval, make a copy */
698 				if (!*copies_param || !(*copies_param)[i]) {
699 					if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i TSRMLS_CC)) {
700 						SET_OOM_ERROR(*stmt->error_info);
701 						goto end;
702 					}
703 				}
704 				break;
705 			}
706 		}
707 
708 		switch (stmt->param_bind[i].type) {
709 			case MYSQL_TYPE_DOUBLE:
710 				*data_size += 8;
711 				if (Z_TYPE_P(the_var) != IS_DOUBLE) {
712 					if (!*copies_param || !(*copies_param)[i]) {
713 						if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i TSRMLS_CC)) {
714 							SET_OOM_ERROR(*stmt->error_info);
715 							goto end;
716 						}
717 					}
718 				}
719 				break;
720 			case MYSQL_TYPE_LONGLONG:
721 				is_longlong = 4;
722 				/* fall-through */
723 			case MYSQL_TYPE_LONG:
724 				{
725 					zval *tmp_data = (*copies_param && (*copies_param)[i])? (*copies_param)[i]: stmt->param_bind[i].zv;
726 					if (Z_TYPE_P(tmp_data) == IS_STRING) {
727 						goto use_string;
728 					}
729 					convert_to_long_ex(&tmp_data);
730 				}
731 				*data_size += 4 + is_longlong;
732 				break;
733 			case MYSQL_TYPE_LONG_BLOB:
734 				if (!(stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED)) {
735 					/*
736 					  User hasn't sent anything, we will send empty string.
737 					  Empty string has length of 0, encoded in 1 byte. No real
738 					  data will follows after it.
739 					*/
740 					(*data_size)++;
741 				}
742 				break;
743 			case MYSQL_TYPE_VAR_STRING:
744 use_string:
745 				*data_size += 8; /* max 8 bytes for size */
746 				if (Z_TYPE_P(the_var) != IS_STRING) {
747 					if (!*copies_param || !(*copies_param)[i]) {
748 						if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i TSRMLS_CC)) {
749 							SET_OOM_ERROR(*stmt->error_info);
750 							goto end;
751 						}
752 					}
753 					the_var = (*copies_param)[i];
754 				}
755 				convert_to_string_ex(&the_var);
756 				*data_size += Z_STRLEN_P(the_var);
757 				break;
758 		}
759 	}
760 	DBG_RETURN(PASS);
761 end:
762 	DBG_RETURN(FAIL);
763 }
764 /* }}} */
765 
766 
767 /* {{{ mysqlnd_stmt_execute_store_param_values */
768 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)769 mysqlnd_stmt_execute_store_param_values(MYSQLND_STMT_DATA * stmt, zval ** copies, zend_uchar * buf, zend_uchar ** p, size_t null_byte_offset)
770 {
771 	unsigned int i;
772 	for (i = 0; i < stmt->param_count; i++) {
773 		zval * data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv;
774 		/* Handle long data */
775 		if (stmt->param_bind[i].zv && Z_TYPE_P(data) == IS_NULL) {
776 			(buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7));
777 		} else {
778 			switch (stmt->param_bind[i].type) {
779 				case MYSQL_TYPE_DOUBLE:
780 					convert_to_double_ex(&data);
781 					float8store(*p, Z_DVAL_P(data));
782 					(*p) += 8;
783 					break;
784 				case MYSQL_TYPE_LONGLONG:
785 					if (Z_TYPE_P(data) == IS_STRING) {
786 						goto send_string;
787 					}
788 					/* data has alreade been converted to long */
789 					int8store(*p, Z_LVAL_P(data));
790 					(*p) += 8;
791 					break;
792 				case MYSQL_TYPE_LONG:
793 					if (Z_TYPE_P(data) == IS_STRING) {
794 						goto send_string;
795 					}
796 					/* data has alreade been converted to long */
797 					int4store(*p, Z_LVAL_P(data));
798 					(*p) += 4;
799 					break;
800 				case MYSQL_TYPE_LONG_BLOB:
801 					if (stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED) {
802 						stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
803 					} else {
804 						/* send_long_data() not called, send empty string */
805 						*p = php_mysqlnd_net_store_length(*p, 0);
806 					}
807 					break;
808 				case MYSQL_TYPE_VAR_STRING:
809 send_string:
810 					{
811 						size_t len = Z_STRLEN_P(data);
812 						/* to is after p. The latter hasn't been moved */
813 						*p = php_mysqlnd_net_store_length(*p, len);
814 						memcpy(*p, Z_STRVAL_P(data), len);
815 						(*p) += len;
816 					}
817 					break;
818 				default:
819 					/* Won't happen, but set to NULL */
820 					(buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7));
821 					break;
822 			}
823 		}
824 	}
825 }
826 /* }}} */
827 
828 
829 /* {{{ mysqlnd_stmt_execute_store_params */
830 static enum_func_status
mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s,zend_uchar ** buf,zend_uchar ** p,size_t * buf_len TSRMLS_DC)831 mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar **p, size_t *buf_len  TSRMLS_DC)
832 {
833 	MYSQLND_STMT_DATA * stmt = s->data;
834 	unsigned int i = 0;
835 	zend_uchar * provided_buffer = *buf;
836 	size_t data_size = 0;
837 	zval **copies = NULL;/* if there are different types */
838 	enum_func_status ret = FAIL;
839 	int resend_types_next_time = 0;
840 	size_t null_byte_offset;
841 
842 	DBG_ENTER("mysqlnd_stmt_execute_store_params");
843 
844 	{
845 		unsigned int null_count = (stmt->param_count + 7) / 8;
846 		if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, null_count TSRMLS_CC)) {
847 			SET_OOM_ERROR(*stmt->error_info);
848 			goto end;
849 		}
850 		/* put `null` bytes */
851 		null_byte_offset = *p - *buf;
852 		memset(*p, 0, null_count);
853 		*p += null_count;
854 	}
855 
856 /* 1. Store type information */
857 	/*
858 	  check if need to send the types even if stmt->send_types_to_server is 0. This is because
859 	  if we send "i" (42) then the type will be int and the server will expect int. However, if next
860 	  time we try to send > LONG_MAX, the conversion to string will send a string and the server
861 	  won't expect it and interpret the value as 0. Thus we need to resend the types, if any such values
862 	  occur, and force resend for the next execution.
863 	*/
864 	if (FAIL == mysqlnd_stmt_execute_prepare_param_types(stmt, &copies, &resend_types_next_time TSRMLS_CC)) {
865 		goto end;
866 	}
867 
868 	int1store(*p, stmt->send_types_to_server);
869 	(*p)++;
870 
871 	if (stmt->send_types_to_server) {
872 		if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, stmt->param_count * 2 TSRMLS_CC)) {
873 			SET_OOM_ERROR(*stmt->error_info);
874 			goto end;
875 		}
876 		mysqlnd_stmt_execute_store_types(stmt, copies, p);
877 	}
878 
879 	stmt->send_types_to_server = resend_types_next_time;
880 
881 /* 2. Store data */
882 	/* 2.1 Calculate how much space we need */
883 	if (FAIL == mysqlnd_stmt_execute_calculate_param_values_size(stmt, &copies, &data_size TSRMLS_CC)) {
884 		goto end;
885 	}
886 
887 	/* 2.2 Enlarge the buffer, if needed */
888 	if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, data_size TSRMLS_CC)) {
889 		SET_OOM_ERROR(*stmt->error_info);
890 		goto end;
891 	}
892 
893 	/* 2.3 Store the actual data */
894 	mysqlnd_stmt_execute_store_param_values(stmt, copies, *buf, p, null_byte_offset);
895 
896 	ret = PASS;
897 end:
898 	mysqlnd_stmt_free_copies(stmt, copies TSRMLS_CC);
899 
900 	DBG_INF_FMT("ret=%s", ret == PASS? "PASS":"FAIL");
901 	DBG_RETURN(ret);
902 }
903 /* }}} */
904 
905 
906 /* {{{ mysqlnd_stmt_execute_generate_request */
907 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)908 mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * const s, zend_uchar ** request, size_t *request_len, zend_bool * free_buffer TSRMLS_DC)
909 {
910 	MYSQLND_STMT_DATA * stmt = s->data;
911 	zend_uchar	*p = stmt->execute_cmd_buffer.buffer,
912 				*cmd_buffer = stmt->execute_cmd_buffer.buffer;
913 	size_t cmd_buffer_length = stmt->execute_cmd_buffer.length;
914 	enum_func_status ret;
915 
916 	DBG_ENTER("mysqlnd_stmt_execute_generate_request");
917 
918 	int4store(p, stmt->stmt_id);
919 	p += 4;
920 
921 	/* flags is 4 bytes, we store just 1 */
922 	int1store(p, (zend_uchar) stmt->flags);
923 	p++;
924 
925 	/* Make it all zero */
926 	int4store(p, 0);
927 
928 	int1store(p, 1); /* and send 1 for iteration count */
929 	p+= 4;
930 
931 	ret = mysqlnd_stmt_execute_store_params(s, &cmd_buffer, &p, &cmd_buffer_length TSRMLS_CC);
932 
933 	*free_buffer = (cmd_buffer != stmt->execute_cmd_buffer.buffer);
934 	*request_len = (p - cmd_buffer);
935 	*request = cmd_buffer;
936 	DBG_INF_FMT("ret=%s", ret == PASS? "PASS":"FAIL");
937 	DBG_RETURN(ret);
938 }
939 /* }}} */
940 
941 /*
942  * Local variables:
943  * tab-width: 4
944  * c-basic-offset: 4
945  * End:
946  * vim600: noet sw=4 ts=4 fdm=marker
947  * vim<600: noet sw=4 ts=4
948  */
949