xref: /PHP-7.3/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 <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, MYSQLND_LLU_SPEC, 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, MYSQLND_LLU_SPEC, 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, MYSQLND_LL_SPEC, 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 				convert_to_string_ex(the_var);
781 				*data_size += Z_STRLEN_P(the_var);
782 				break;
783 		}
784 	}
785 	DBG_RETURN(PASS);
786 end:
787 	DBG_RETURN(FAIL);
788 }
789 /* }}} */
790 
791 
792 /* {{{ mysqlnd_stmt_execute_store_param_values */
793 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)794 mysqlnd_stmt_execute_store_param_values(MYSQLND_STMT_DATA * stmt, zval * copies, zend_uchar * buf, zend_uchar ** p, size_t null_byte_offset)
795 {
796 	unsigned int i;
797 	for (i = 0; i < stmt->param_count; i++) {
798 		zval *data, *parameter = &stmt->param_bind[i].zv;
799 
800 		ZVAL_DEREF(parameter);
801 		data = (copies && !Z_ISUNDEF(copies[i]))? &copies[i]: parameter;
802 		/* Handle long data */
803 		if (!Z_ISUNDEF_P(parameter) && Z_TYPE_P(data) == IS_NULL) {
804 			(buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7));
805 		} else {
806 			switch (stmt->param_bind[i].type) {
807 				case MYSQL_TYPE_DOUBLE:
808 					convert_to_double_ex(data);
809 					float8store(*p, Z_DVAL_P(data));
810 					(*p) += 8;
811 					break;
812 				case MYSQL_TYPE_LONGLONG:
813 					if (Z_TYPE_P(data) == IS_STRING) {
814 						goto send_string;
815 					}
816 					/* data has alreade been converted to long */
817 					int8store(*p, Z_LVAL_P(data));
818 					(*p) += 8;
819 					break;
820 				case MYSQL_TYPE_LONG:
821 					if (Z_TYPE_P(data) == IS_STRING) {
822 						goto send_string;
823 					}
824 					/* data has alreade been converted to long */
825 					int4store(*p, Z_LVAL_P(data));
826 					(*p) += 4;
827 					break;
828 				case MYSQL_TYPE_TINY:
829 					if (Z_TYPE_P(data) == IS_STRING) {
830 						goto send_string;
831 					}
832 					int1store(*p, Z_LVAL_P(data));
833 					(*p)++;
834 					break;
835 				case MYSQL_TYPE_LONG_BLOB:
836 					if (stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED) {
837 						stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
838 					} else {
839 						/* send_long_data() not called, send empty string */
840 						*p = php_mysqlnd_net_store_length(*p, 0);
841 					}
842 					break;
843 				case MYSQL_TYPE_VAR_STRING:
844 send_string:
845 					{
846 						const size_t len = Z_STRLEN_P(data);
847 						/* to is after p. The latter hasn't been moved */
848 						*p = php_mysqlnd_net_store_length(*p, len);
849 						memcpy(*p, Z_STRVAL_P(data), len);
850 						(*p) += len;
851 					}
852 					break;
853 				default:
854 					/* Won't happen, but set to NULL */
855 					(buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7));
856 					break;
857 			}
858 		}
859 	}
860 }
861 /* }}} */
862 
863 
864 /* {{{ mysqlnd_stmt_execute_store_params */
865 static enum_func_status
mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s,zend_uchar ** buf,zend_uchar ** p,size_t * buf_len)866 mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar **p, size_t *buf_len )
867 {
868 	MYSQLND_STMT_DATA * stmt = s->data;
869 	zend_uchar * provided_buffer = *buf;
870 	size_t data_size = 0;
871 	zval *copies = NULL;/* if there are different types */
872 	enum_func_status ret = FAIL;
873 	int resend_types_next_time = 0;
874 	size_t null_byte_offset;
875 
876 	DBG_ENTER("mysqlnd_stmt_execute_store_params");
877 
878 	{
879 		unsigned int null_count = (stmt->param_count + 7) / 8;
880 		if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, null_count)) {
881 			SET_OOM_ERROR(stmt->error_info);
882 			goto end;
883 		}
884 		/* put `null` bytes */
885 		null_byte_offset = *p - *buf;
886 		memset(*p, 0, null_count);
887 		*p += null_count;
888 	}
889 
890 /* 1. Store type information */
891 	/*
892 	  check if need to send the types even if stmt->send_types_to_server is 0. This is because
893 	  if we send "i" (42) then the type will be int and the server will expect int. However, if next
894 	  time we try to send > LONG_MAX, the conversion to string will send a string and the server
895 	  won't expect it and interpret the value as 0. Thus we need to resend the types, if any such values
896 	  occur, and force resend for the next execution.
897 	*/
898 	if (FAIL == mysqlnd_stmt_execute_prepare_param_types(stmt, &copies, &resend_types_next_time)) {
899 		goto end;
900 	}
901 
902 	int1store(*p, stmt->send_types_to_server);
903 	(*p)++;
904 
905 	if (stmt->send_types_to_server) {
906 		if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, stmt->param_count * 2)) {
907 			SET_OOM_ERROR(stmt->error_info);
908 			goto end;
909 		}
910 		mysqlnd_stmt_execute_store_types(stmt, copies, p);
911 	}
912 
913 	stmt->send_types_to_server = resend_types_next_time;
914 
915 /* 2. Store data */
916 	/* 2.1 Calculate how much space we need */
917 	if (FAIL == mysqlnd_stmt_execute_calculate_param_values_size(stmt, &copies, &data_size)) {
918 		goto end;
919 	}
920 
921 	/* 2.2 Enlarge the buffer, if needed */
922 	if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, data_size)) {
923 		SET_OOM_ERROR(stmt->error_info);
924 		goto end;
925 	}
926 
927 	/* 2.3 Store the actual data */
928 	mysqlnd_stmt_execute_store_param_values(stmt, copies, *buf, p, null_byte_offset);
929 
930 	ret = PASS;
931 end:
932 	mysqlnd_stmt_free_copies(stmt, copies);
933 
934 	DBG_INF_FMT("ret=%s", ret == PASS? "PASS":"FAIL");
935 	DBG_RETURN(ret);
936 }
937 /* }}} */
938 
939 
940 /* {{{ mysqlnd_stmt_execute_generate_request */
941 enum_func_status
mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * const s,zend_uchar ** request,size_t * request_len,zend_bool * free_buffer)942 mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * const s, zend_uchar ** request, size_t *request_len, zend_bool * free_buffer)
943 {
944 	MYSQLND_STMT_DATA * stmt = s->data;
945 	zend_uchar	*p = stmt->execute_cmd_buffer.buffer,
946 				*cmd_buffer = stmt->execute_cmd_buffer.buffer;
947 	size_t cmd_buffer_length = stmt->execute_cmd_buffer.length;
948 	enum_func_status ret = PASS;
949 
950 	DBG_ENTER("mysqlnd_stmt_execute_generate_request");
951 
952 	int4store(p, stmt->stmt_id);
953 	p += 4;
954 
955 	/* flags is 4 bytes, we store just 1 */
956 	int1store(p, (zend_uchar) stmt->flags);
957 	p++;
958 
959 	/* Make it all zero */
960 	int4store(p, 0);
961 
962 	int1store(p, 1); /* and send 1 for iteration count */
963 	p+= 4;
964 
965 	if (stmt->param_count != 0) {
966 	    ret = mysqlnd_stmt_execute_store_params(s, &cmd_buffer, &p, &cmd_buffer_length);
967 	}
968 
969 	*free_buffer = (cmd_buffer != stmt->execute_cmd_buffer.buffer);
970 	*request_len = (p - cmd_buffer);
971 	*request = cmd_buffer;
972 	DBG_INF_FMT("ret=%s", ret == PASS? "PASS":"FAIL");
973 	DBG_RETURN(ret);
974 }
975 /* }}} */
976 
977 /*
978  * Local variables:
979  * tab-width: 4
980  * c-basic-offset: 4
981  * End:
982  * vim600: noet sw=4 ts=4 fdm=marker
983  * vim<600: noet sw=4 ts=4
984  */
985