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