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