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