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