Busybox: Upgrade to 1.21.1 (stable). lsof active.
[tomato.git] / release / src / router / php / ext / mysqlnd / mysqlnd_ps_codec.c
blob5ead1b0bcced2e4c68523fa91ecdd8d50253b1dc
1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2006-2013 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Andrey Hristov <andrey@mysql.com> |
16 | Ulf Wendel <uwendel@mysql.com> |
17 | Georg Richter <georg@mysql.com> |
18 +----------------------------------------------------------------------+
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"
28 #define MYSQLND_SILENT
31 enum mysqlnd_timestamp_type
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
41 struct st_mysqlnd_time
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;
50 struct st_mysqlnd_perm_bind mysqlnd_ps_fetch_functions[MYSQL_TYPE_LAST + 1];
52 #define MYSQLND_PS_SKIP_RESULT_W_LEN -1
53 #define MYSQLND_PS_SKIP_RESULT_STR -2
55 /* {{{ ps_fetch_from_1_to_8_bytes */
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)
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;
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;
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 */
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);
93 } else {
94 /* SIGNED */
95 int64_t lval = 0;
96 switch (byte_count) {
97 case 8:lval = (int64_t) sint8korr(*row);break;
99 7, 6 and 5 are not possible.
100 BIT is only unsigned, thus only uint5|6|7 macroses exist
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;
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 */
115 ZVAL_LONG(zv, (long) lval); /* the cast is safe, we are in the range */
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
127 DBG_INF("stringify");
128 ZVAL_STRINGL(zv, tmp, tmp_len, 1);
131 (*row)+= byte_count;
132 DBG_VOID_RETURN;
134 /* }}} */
137 /* {{{ ps_fetch_null */
138 static
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)
143 ZVAL_NULL(zv);
145 /* }}} */
148 /* {{{ ps_fetch_int8 */
149 static
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)
154 ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, 1 TSRMLS_CC);
156 /* }}} */
159 /* {{{ ps_fetch_int16 */
160 static
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)
165 ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, 2 TSRMLS_CC);
167 /* }}} */
170 /* {{{ ps_fetch_int32 */
171 static
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)
176 ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, 4 TSRMLS_CC);
178 /* }}} */
181 /* {{{ ps_fetch_int64 */
182 static
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)
187 ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, 8 TSRMLS_CC);
189 /* }}} */
192 /* {{{ ps_fetch_float */
193 static
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)
198 float value;
199 DBG_ENTER("ps_fetch_float");
200 float4get(value, *row);
201 ZVAL_DOUBLE(zv, value);
202 (*row)+= 4;
203 DBG_INF_FMT("value=%f", value);
204 DBG_VOID_RETURN;
206 /* }}} */
209 /* {{{ ps_fetch_double */
210 static
211 void ps_fetch_double(zval *zv, const MYSQLND_FIELD * const field,
212 unsigned int pack_len, zend_uchar **row,
213 zend_bool as_unicode TSRMLS_DC)
215 double value;
216 DBG_ENTER("ps_fetch_double");
217 float8get(value, *row);
218 ZVAL_DOUBLE(zv, value);
219 (*row)+= 8;
220 DBG_INF_FMT("value=%f", value);
221 DBG_VOID_RETURN;
223 /* }}} */
226 /* {{{ ps_fetch_time */
227 static
228 void ps_fetch_time(zval *zv, const MYSQLND_FIELD * const field,
229 unsigned int pack_len, zend_uchar **row,
230 zend_bool as_unicode TSRMLS_DC)
232 struct st_mysqlnd_time t;
233 unsigned int length; /* First byte encodes the length*/
234 char * value;
235 DBG_ENTER("ps_fetch_time");
237 if ((length = php_mysqlnd_net_field_length(row))) {
238 zend_uchar *to= *row;
240 t.time_type = MYSQLND_TIMESTAMP_TIME;
241 t.neg = (zend_bool) to[0];
243 t.day = (unsigned long) sint4korr(to+1);
244 t.hour = (unsigned int) to[5];
245 t.minute = (unsigned int) to[6];
246 t.second = (unsigned int) to[7];
247 t.second_part = (length > 8) ? (unsigned long) sint4korr(to+8) : 0;
248 t.year = t.month= 0;
249 if (t.day) {
250 /* Convert days to hours at once */
251 t.hour += t.day*24;
252 t.day = 0;
255 (*row) += length;
256 } else {
257 memset(&t, 0, sizeof(t));
258 t.time_type = MYSQLND_TIMESTAMP_TIME;
261 length = mnd_sprintf(&value, 0, "%s%02u:%02u:%02u", (t.neg ? "-" : ""), t.hour, t.minute, t.second);
263 DBG_INF_FMT("%s", value);
264 #if MYSQLND_UNICODE
265 if (!as_unicode) {
266 #endif
267 ZVAL_STRINGL(zv, value, length, 1);
268 mnd_sprintf_free(value);
269 #if MYSQLND_UNICODE
270 } else {
271 ZVAL_UTF8_STRINGL(zv, value, length, ZSTR_AUTOFREE);
273 #endif
274 DBG_VOID_RETURN;
276 /* }}} */
279 /* {{{ ps_fetch_date */
280 static
281 void ps_fetch_date(zval *zv, const MYSQLND_FIELD * const field,
282 unsigned int pack_len, zend_uchar **row,
283 zend_bool as_unicode TSRMLS_DC)
285 struct st_mysqlnd_time t = {0};
286 unsigned int length; /* First byte encodes the length*/
287 char * value;
288 DBG_ENTER("ps_fetch_date");
290 if ((length = php_mysqlnd_net_field_length(row))) {
291 zend_uchar *to= *row;
293 t.time_type= MYSQLND_TIMESTAMP_DATE;
294 t.neg= 0;
296 t.second_part = t.hour = t.minute = t.second = 0;
298 t.year = (unsigned int) sint2korr(to);
299 t.month = (unsigned int) to[2];
300 t.day = (unsigned int) to[3];
302 (*row)+= length;
303 } else {
304 memset(&t, 0, sizeof(t));
305 t.time_type = MYSQLND_TIMESTAMP_DATE;
308 length = mnd_sprintf(&value, 0, "%04u-%02u-%02u", t.year, t.month, t.day);
310 DBG_INF_FMT("%s", value);
311 #if MYSQLND_UNICODE
312 if (!as_unicode) {
313 #endif
314 ZVAL_STRINGL(zv, value, length, 1);
315 mnd_sprintf_free(value);
316 #if MYSQLND_UNICODE
317 } else {
318 ZVAL_UTF8_STRINGL(zv, value, length, ZSTR_AUTOFREE);
320 #endif
321 DBG_VOID_RETURN;
323 /* }}} */
326 /* {{{ ps_fetch_datetime */
327 static
328 void ps_fetch_datetime(zval *zv, const MYSQLND_FIELD * const field,
329 unsigned int pack_len, zend_uchar **row,
330 zend_bool as_unicode TSRMLS_DC)
332 struct st_mysqlnd_time t;
333 unsigned int length; /* First byte encodes the length*/
334 char * value;
335 DBG_ENTER("ps_fetch_datetime");
337 if ((length = php_mysqlnd_net_field_length(row))) {
338 zend_uchar *to= *row;
340 t.time_type = MYSQLND_TIMESTAMP_DATETIME;
341 t.neg = 0;
343 t.year = (unsigned int) sint2korr(to);
344 t.month = (unsigned int) to[2];
345 t.day = (unsigned int) to[3];
347 if (length > 4) {
348 t.hour = (unsigned int) to[4];
349 t.minute = (unsigned int) to[5];
350 t.second = (unsigned int) to[6];
351 } else {
352 t.hour = t.minute = t.second= 0;
354 t.second_part = (length > 7) ? (unsigned long) sint4korr(to+7) : 0;
356 (*row)+= length;
357 } else {
358 memset(&t, 0, sizeof(t));
359 t.time_type = MYSQLND_TIMESTAMP_DATETIME;
362 length = mnd_sprintf(&value, 0, "%04u-%02u-%02u %02u:%02u:%02u", t.year, t.month, t.day, t.hour, t.minute, t.second);
364 DBG_INF_FMT("%s", value);
365 #if MYSQLND_UNICODE
366 if (!as_unicode) {
367 #endif
368 ZVAL_STRINGL(zv, value, length, 1);
369 mnd_sprintf_free(value);
370 #if MYSQLND_UNICODE
371 } else {
372 ZVAL_UTF8_STRINGL(zv, to, length, ZSTR_AUTOFREE);
374 #endif
375 DBG_VOID_RETURN;
377 /* }}} */
380 /* {{{ ps_fetch_string */
381 static
382 void ps_fetch_string(zval *zv, const MYSQLND_FIELD * const field,
383 unsigned int pack_len, zend_uchar **row,
384 zend_bool as_unicode TSRMLS_DC)
387 For now just copy, before we make it possible
388 to write \0 to the row buffer
390 unsigned long length = php_mysqlnd_net_field_length(row);
391 DBG_ENTER("ps_fetch_string");
392 DBG_INF_FMT("len = %lu", length);
393 #if MYSQLND_UNICODE
394 if (field->charsetnr == MYSQLND_BINARY_CHARSET_NR) {
395 DBG_INF("Binary charset");
396 ZVAL_STRINGL(zv, (char *)*row, length, 1);
397 } else {
398 DBG_INF_FMT("copying from the row buffer");
399 ZVAL_UTF8_STRINGL(zv, (char*)*row, length, ZSTR_DUPLICATE);
401 #else
402 DBG_INF("copying from the row buffer");
403 ZVAL_STRINGL(zv, (char *)*row, length, 1);
404 #endif
406 (*row) += length;
407 DBG_VOID_RETURN;
409 /* }}} */
412 /* {{{ ps_fetch_bit */
413 static
414 void ps_fetch_bit(zval *zv, const MYSQLND_FIELD * const field,
415 unsigned int pack_len, zend_uchar **row,
416 zend_bool as_unicode TSRMLS_DC)
418 unsigned long length= php_mysqlnd_net_field_length(row);
419 ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, length TSRMLS_CC);
421 /* }}} */
424 /* {{{ _mysqlnd_init_ps_fetch_subsystem */
425 void _mysqlnd_init_ps_fetch_subsystem()
427 memset(mysqlnd_ps_fetch_functions, 0, sizeof(mysqlnd_ps_fetch_functions));
428 mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].func = ps_fetch_null;
429 mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].pack_len = 0;
430 mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].php_type = IS_NULL;
431 mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].can_ret_as_str_in_uni = TRUE;
433 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].func = ps_fetch_int8;
434 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].pack_len = 1;
435 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].php_type = IS_LONG;
436 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].can_ret_as_str_in_uni = TRUE;
438 mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].func = ps_fetch_int16;
439 mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].pack_len = 2;
440 mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].php_type = IS_LONG;
441 mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].can_ret_as_str_in_uni = TRUE;
443 mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].func = ps_fetch_int16;
444 mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].pack_len = 2;
445 mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].php_type = IS_LONG;
446 mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].can_ret_as_str_in_uni = TRUE;
448 mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].func = ps_fetch_int32;
449 mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].pack_len = 4;
450 mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].php_type = IS_LONG;
451 mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].can_ret_as_str_in_uni = TRUE;
453 mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].func = ps_fetch_int32;
454 mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].pack_len = 4;
455 mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].php_type = IS_LONG;
456 mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].can_ret_as_str_in_uni = TRUE;
458 mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].func = ps_fetch_int64;
459 mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].pack_len= 8;
460 mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].php_type= IS_LONG;
461 mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].can_ret_as_str_in_uni = TRUE;
463 mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].func = ps_fetch_float;
464 mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].pack_len = 4;
465 mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].php_type = IS_DOUBLE;
466 mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].can_ret_as_str_in_uni = TRUE;
468 mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].func = ps_fetch_double;
469 mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].pack_len = 8;
470 mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].php_type = IS_DOUBLE;
471 mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].can_ret_as_str_in_uni = TRUE;
473 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].func = ps_fetch_time;
474 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].pack_len = MYSQLND_PS_SKIP_RESULT_W_LEN;
475 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].php_type = IS_STRING;
476 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].can_ret_as_str_in_uni = TRUE;
478 mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].func = ps_fetch_date;
479 mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].pack_len = MYSQLND_PS_SKIP_RESULT_W_LEN;
480 mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].php_type = IS_STRING;
481 mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].can_ret_as_str_in_uni = TRUE;
483 mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].func = ps_fetch_string;
484 mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].pack_len = MYSQLND_PS_SKIP_RESULT_W_LEN;
485 mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].php_type = IS_STRING;
486 mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].can_ret_as_str_in_uni = TRUE;
488 mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].func = ps_fetch_datetime;
489 mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].pack_len= MYSQLND_PS_SKIP_RESULT_W_LEN;
490 mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].php_type= IS_STRING;
491 mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].can_ret_as_str_in_uni = TRUE;
493 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].func = ps_fetch_datetime;
494 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].pack_len= MYSQLND_PS_SKIP_RESULT_W_LEN;
495 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].php_type= IS_STRING;
496 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].can_ret_as_str_in_uni = TRUE;
498 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].func = ps_fetch_string;
499 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].pack_len= MYSQLND_PS_SKIP_RESULT_STR;
500 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].php_type = IS_STRING;
501 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].is_possibly_blob = TRUE;
502 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].can_ret_as_str_in_uni = TRUE;
504 mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].func = ps_fetch_string;
505 mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
506 mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].php_type = IS_STRING;
507 mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].is_possibly_blob = TRUE;
508 mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].can_ret_as_str_in_uni = TRUE;
510 mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].func = ps_fetch_string;
511 mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
512 mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].php_type = IS_STRING;
513 mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].is_possibly_blob = TRUE;
514 mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].can_ret_as_str_in_uni = TRUE;
516 mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].func = ps_fetch_string;
517 mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
518 mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].php_type = IS_STRING;
519 mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].is_possibly_blob = TRUE;
520 mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].can_ret_as_str_in_uni = TRUE;
522 mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].func = ps_fetch_bit;
523 mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].pack_len = 8;
524 mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].php_type = IS_LONG;
525 mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].can_ret_as_str_in_uni = TRUE;
527 mysqlnd_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].func = ps_fetch_string;
528 mysqlnd_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
529 mysqlnd_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].php_type = IS_STRING;
530 mysqlnd_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].is_possibly_blob = TRUE;
532 mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].func = ps_fetch_string;
533 mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
534 mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].php_type = IS_STRING;
535 mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].is_possibly_blob = TRUE;
537 mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].func = ps_fetch_string;
538 mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
539 mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].php_type = IS_STRING;
540 mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].is_possibly_blob = TRUE;
542 mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].func = ps_fetch_string;
543 mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
544 mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].php_type = IS_STRING;
545 mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].can_ret_as_str_in_uni = TRUE;
547 mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].func = ps_fetch_string;
548 mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
549 mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].php_type = IS_STRING;
550 mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].can_ret_as_str_in_uni = TRUE;
552 mysqlnd_ps_fetch_functions[MYSQL_TYPE_ENUM].func = ps_fetch_string;
553 mysqlnd_ps_fetch_functions[MYSQL_TYPE_ENUM].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
554 mysqlnd_ps_fetch_functions[MYSQL_TYPE_ENUM].php_type = IS_STRING;
556 mysqlnd_ps_fetch_functions[MYSQL_TYPE_SET].func = ps_fetch_string;
557 mysqlnd_ps_fetch_functions[MYSQL_TYPE_SET].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
558 mysqlnd_ps_fetch_functions[MYSQL_TYPE_SET].php_type = IS_STRING;
560 mysqlnd_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].func = ps_fetch_string;
561 mysqlnd_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].pack_len= MYSQLND_PS_SKIP_RESULT_STR;
562 mysqlnd_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].php_type= IS_STRING;
564 /* }}} */
567 /* {{{ mysqlnd_stmt_copy_it */
568 static enum_func_status
569 mysqlnd_stmt_copy_it(zval *** copies, zval *original, unsigned int param_count, unsigned int current TSRMLS_DC)
571 if (!*copies) {
572 *copies = mnd_ecalloc(param_count, sizeof(zval *));
574 if (*copies) {
575 MAKE_STD_ZVAL((*copies)[current]);
576 *(*copies)[current] = *original;
577 Z_SET_REFCOUNT_P((*copies)[current], 1);
578 zval_copy_ctor((*copies)[current]);
579 return PASS;
581 return FAIL;
583 /* }}} */
586 /* {{{ mysqlnd_stmt_execute_store_params */
587 static enum_func_status
588 mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar **p, size_t *buf_len TSRMLS_DC)
590 MYSQLND_STMT_DATA * stmt = s->data;
591 unsigned int i = 0;
592 zend_uchar * provided_buffer = *buf;
593 size_t left = (*buf_len - (*p - *buf));
594 size_t data_size = 0;
595 zval **copies = NULL;/* if there are different types */
596 enum_func_status ret = FAIL;
597 int resend_types_next_time = 0;
598 size_t null_byte_offset;
600 DBG_ENTER("mysqlnd_stmt_execute_store_params");
603 unsigned int null_count = (stmt->param_count + 7) / 8;
604 /* give it some reserved space - 20 bytes */
605 if (left < (null_count + 20)) {
606 unsigned int offset = *p - *buf;
607 zend_uchar *tmp_buf;
608 *buf_len = offset + null_count + 20;
609 tmp_buf = mnd_emalloc(*buf_len);
610 if (!tmp_buf) {
611 SET_OOM_ERROR(*stmt->error_info);
612 goto end;
614 memcpy(tmp_buf, *buf, offset);
615 if (*buf != provided_buffer) {
616 mnd_efree(*buf);
618 *buf = tmp_buf;
620 /* Update our pos pointer */
621 *p = *buf + offset;
623 /* put `null` bytes */
624 null_byte_offset = *p - *buf;
625 memset(*p, 0, null_count);
626 *p += null_count;
629 /* 1. Store type information */
631 check if need to send the types even if stmt->send_types_to_server is 0. This is because
632 if we send "i" (42) then the type will be int and the server will expect int. However, if next
633 time we try to send > LONG_MAX, the conversion to string will send a string and the server
634 won't expect it and interpret the value as 0. Thus we need to resend the types, if any such values
635 occur, and force resend for the next execution.
637 for (i = 0; i < stmt->param_count; i++) {
638 if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_NULL &&
639 (stmt->param_bind[i].type == MYSQL_TYPE_LONG || stmt->param_bind[i].type == MYSQL_TYPE_LONGLONG))
641 /* always copy the var, because we do many conversions */
642 if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG &&
643 PASS != mysqlnd_stmt_copy_it(&copies, stmt->param_bind[i].zv, stmt->param_count, i TSRMLS_CC))
645 SET_OOM_ERROR(*stmt->error_info);
646 goto end;
649 if it doesn't fit in a long send it as a string.
650 Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX
652 if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG) {
653 zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv;
654 convert_to_double_ex(&tmp_data);
655 if (Z_DVAL_P(tmp_data) > LONG_MAX || Z_DVAL_P(tmp_data) < LONG_MIN) {
656 stmt->send_types_to_server = resend_types_next_time = 1;
662 int1store(*p, stmt->send_types_to_server);
663 (*p)++;
665 if (stmt->send_types_to_server) {
666 /* 2 bytes per type, and leave 20 bytes for future use */
667 if (left < ((stmt->param_count * 2) + 20)) {
668 unsigned int offset = *p - *buf;
669 zend_uchar *tmp_buf;
670 *buf_len = offset + stmt->param_count * 2 + 20;
671 tmp_buf = mnd_emalloc(*buf_len);
672 if (!tmp_buf) {
673 SET_OOM_ERROR(*stmt->error_info);
674 goto end;
676 memcpy(tmp_buf, *buf, offset);
677 if (*buf != provided_buffer) {
678 mnd_efree(*buf);
680 *buf = tmp_buf;
682 /* Update our pos pointer */
683 *p = *buf + offset;
685 for (i = 0; i < stmt->param_count; i++) {
686 short current_type = stmt->param_bind[i].type;
687 /* our types are not unsigned */
688 #if SIZEOF_LONG==8
689 if (current_type == MYSQL_TYPE_LONG) {
690 current_type = MYSQL_TYPE_LONGLONG;
692 #endif
693 if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_NULL && (current_type == MYSQL_TYPE_LONG || current_type == MYSQL_TYPE_LONGLONG)) {
695 if it doesn't fit in a long send it as a string.
696 Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX
698 if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG) {
699 zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv;
701 convert_to_double_ex(&tmp_data);
702 if (Z_DVAL_P(tmp_data) > LONG_MAX || Z_DVAL_P(tmp_data) < LONG_MIN) {
703 convert_to_string_ex(&tmp_data);
704 current_type = MYSQL_TYPE_VAR_STRING;
706 don't change stmt->param_bind[i].type to MYSQL_TYPE_VAR_STRING
707 we force convert_to_long_ex in all cases, thus the type will be right in the next switch.
708 if the type is however not long, then we will do a goto in the next switch.
709 We want to preserve the original bind type given by the user. Thus, we do these hacks.
711 } else {
712 convert_to_long_ex(&tmp_data);
716 int2store(*p, current_type);
717 *p+= 2;
720 stmt->send_types_to_server = resend_types_next_time;
722 /* 2. Store data */
723 /* 2.1 Calculate how much space we need */
724 for (i = 0; i < stmt->param_count; i++) {
725 unsigned int j;
726 zval *the_var = stmt->param_bind[i].zv;
728 if (!the_var || (stmt->param_bind[i].type != MYSQL_TYPE_LONG_BLOB && Z_TYPE_P(the_var) == IS_NULL)) {
729 continue;
731 for (j = i + 1; j < stmt->param_count; j++) {
732 if (stmt->param_bind[j].zv == the_var) {
733 /* Double binding of the same zval, make a copy */
734 if (!copies || !copies[i]) {
735 if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) {
736 SET_OOM_ERROR(*stmt->error_info);
737 goto end;
740 break;
744 switch (stmt->param_bind[i].type) {
745 case MYSQL_TYPE_DOUBLE:
746 data_size += 8;
747 if (Z_TYPE_P(the_var) != IS_DOUBLE) {
748 if (!copies || !copies[i]) {
749 if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) {
750 SET_OOM_ERROR(*stmt->error_info);
751 goto end;
755 break;
756 case MYSQL_TYPE_LONGLONG:
758 zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv;
759 if (Z_TYPE_P(tmp_data) == IS_STRING) {
760 goto use_string;
762 convert_to_long_ex(&tmp_data);
764 data_size += 8;
765 break;
766 case MYSQL_TYPE_LONG:
768 zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv;
769 if (Z_TYPE_P(tmp_data) == IS_STRING) {
770 goto use_string;
772 convert_to_long_ex(&tmp_data);
774 data_size += 4;
775 break;
776 case MYSQL_TYPE_LONG_BLOB:
777 if (!(stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED)) {
779 User hasn't sent anything, we will send empty string.
780 Empty string has length of 0, encoded in 1 byte. No real
781 data will follows after it.
783 data_size++;
785 break;
786 case MYSQL_TYPE_VAR_STRING:
787 use_string:
788 data_size += 8; /* max 8 bytes for size */
789 #if MYSQLND_UNICODE
790 if (Z_TYPE_P(the_var) != IS_STRING || Z_TYPE_P(the_var) == IS_UNICODE)
791 #else
792 if (Z_TYPE_P(the_var) != IS_STRING)
793 #endif
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;
801 the_var = copies[i];
802 #if MYSQLND_UNICODE
803 if (Z_TYPE_P(the_var) == IS_UNICODE) {
804 zval_unicode_to_string_ex(the_var, UG(utf8_conv) TSRMLS_CC);
806 #endif
808 convert_to_string_ex(&the_var);
809 data_size += Z_STRLEN_P(the_var);
810 break;
814 /* 2.2 Enlarge the buffer, if needed */
815 left = (*buf_len - (*p - *buf));
816 if (left < data_size) {
817 unsigned int offset = *p - *buf;
818 zend_uchar *tmp_buf;
819 *buf_len = offset + data_size + 10; /* Allocate + 10 for safety */
820 tmp_buf = mnd_emalloc(*buf_len);
821 if (!tmp_buf) {
822 SET_OOM_ERROR(*stmt->error_info);
823 goto end;
825 memcpy(tmp_buf, *buf, offset);
827 When too many columns the buffer provided to the function might not be sufficient.
828 In this case new buffer has been allocated above. When we allocate a buffer and then
829 allocate a bigger one here, we should free the first one.
831 if (*buf != provided_buffer) {
832 mnd_efree(*buf);
834 *buf = tmp_buf;
835 /* Update our pos pointer */
836 *p = *buf + offset;
839 /* 2.3 Store the actual data */
840 for (i = 0; i < stmt->param_count; i++) {
841 zval *data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv;
842 /* Handle long data */
843 if (stmt->param_bind[i].zv && Z_TYPE_P(data) == IS_NULL) {
844 (*buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7));
845 } else {
846 switch (stmt->param_bind[i].type) {
847 case MYSQL_TYPE_DOUBLE:
848 convert_to_double_ex(&data);
849 float8store(*p, Z_DVAL_P(data));
850 (*p) += 8;
851 break;
852 case MYSQL_TYPE_LONGLONG:
853 if (Z_TYPE_P(data) == IS_STRING) {
854 goto send_string;
856 /* data has alreade been converted to long */
857 int8store(*p, Z_LVAL_P(data));
858 (*p) += 8;
859 break;
860 case MYSQL_TYPE_LONG:
861 if (Z_TYPE_P(data) == IS_STRING) {
862 goto send_string;
864 /* data has alreade been converted to long */
865 int4store(*p, Z_LVAL_P(data));
866 (*p) += 4;
867 break;
868 case MYSQL_TYPE_LONG_BLOB:
869 if (stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED) {
870 stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
871 } else {
872 /* send_long_data() not called, send empty string */
873 *p = php_mysqlnd_net_store_length(*p, 0);
875 break;
876 case MYSQL_TYPE_VAR_STRING:
877 send_string:
879 unsigned int len = Z_STRLEN_P(data);
880 /* to is after p. The latter hasn't been moved */
881 *p = php_mysqlnd_net_store_length(*p, len);
882 memcpy(*p, Z_STRVAL_P(data), len);
883 (*p) += len;
885 break;
886 default:
887 /* Won't happen, but set to NULL */
888 (*buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7));
889 break;
893 ret = PASS;
894 end:
895 if (copies) {
896 for (i = 0; i < stmt->param_count; i++) {
897 if (copies[i]) {
898 zval_ptr_dtor(&copies[i]);
901 mnd_efree(copies);
904 DBG_INF_FMT("ret=%s", ret == PASS? "PASS":"FAIL");
905 DBG_RETURN(ret);
907 /* }}} */
910 /* {{{ mysqlnd_stmt_execute_generate_request */
911 enum_func_status
912 mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * const s, zend_uchar ** request, size_t *request_len, zend_bool * free_buffer TSRMLS_DC)
914 MYSQLND_STMT_DATA * stmt = s->data;
915 zend_uchar *p = stmt->execute_cmd_buffer.buffer,
916 *cmd_buffer = stmt->execute_cmd_buffer.buffer;
917 size_t cmd_buffer_length = stmt->execute_cmd_buffer.length;
918 enum_func_status ret;
920 DBG_ENTER("mysqlnd_stmt_execute_generate_request");
922 int4store(p, stmt->stmt_id);
923 p += 4;
925 /* flags is 4 bytes, we store just 1 */
926 int1store(p, (zend_uchar) stmt->flags);
927 p++;
929 /* Make it all zero */
930 int4store(p, 0);
932 int1store(p, 1); /* and send 1 for iteration count */
933 p+= 4;
935 ret = mysqlnd_stmt_execute_store_params(s, &cmd_buffer, &p, &cmd_buffer_length TSRMLS_CC);
937 *free_buffer = (cmd_buffer != stmt->execute_cmd_buffer.buffer);
938 *request_len = (p - cmd_buffer);
939 *request = cmd_buffer;
940 DBG_INF_FMT("ret=%s", ret == PASS? "PASS":"FAIL");
941 DBG_RETURN(ret);
943 /* }}} */
946 * Local variables:
947 * tab-width: 4
948 * c-basic-offset: 4
949 * End:
950 * vim600: noet sw=4 ts=4 fdm=marker
951 * vim<600: noet sw=4 ts=4