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