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