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