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