Annotation of embedaddon/php/ext/mysqlnd/mysqlnd_ps_codec.c, revision 1.1.1.2
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 2006-2012 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: +----------------------------------------------------------------------+
1.1.1.2 ! misho 15: | Authors: Andrey Hristov <andrey@mysql.com> |
1.1 misho 16: | Ulf Wendel <uwendel@mysql.com> |
1.1.1.2 ! misho 17: | Georg Richter <georg@mysql.com> |
1.1 misho 18: +----------------------------------------------------------------------+
19: */
20:
1.1.1.2 ! misho 21: /* $Id$ */
1.1 misho 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 */
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
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
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
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
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
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
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 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;
205: }
206: /* }}} */
207:
208:
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)
214: {
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;
222: }
223: /* }}} */
224:
225:
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)
231: {
232: struct st_mysqlnd_time t;
233: unsigned int length; /* First byte encodes the length*/
234: char * value;
235: DBG_ENTER("ps_fetch_time");
236:
237: if ((length = php_mysqlnd_net_field_length(row))) {
238: zend_uchar *to= *row;
239:
240: t.time_type = MYSQLND_TIMESTAMP_TIME;
241: t.neg = (zend_bool) to[0];
242:
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;
253: }
254:
255: (*row) += length;
256: } else {
257: memset(&t, 0, sizeof(t));
258: t.time_type = MYSQLND_TIMESTAMP_TIME;
259: }
260:
1.1.1.2 ! misho 261: length = mnd_sprintf(&value, 0, "%s%02u:%02u:%02u", (t.neg ? "-" : ""), t.hour, t.minute, t.second);
1.1 misho 262:
263: DBG_INF_FMT("%s", value);
264: #if MYSQLND_UNICODE
265: if (!as_unicode) {
266: #endif
267: ZVAL_STRINGL(zv, value, length, 1);
1.1.1.2 ! misho 268: mnd_sprintf_free(value);
1.1 misho 269: #if MYSQLND_UNICODE
270: } else {
271: ZVAL_UTF8_STRINGL(zv, value, length, ZSTR_AUTOFREE);
272: }
273: #endif
274: DBG_VOID_RETURN;
275: }
276: /* }}} */
277:
278:
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)
284: {
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");
289:
290: if ((length = php_mysqlnd_net_field_length(row))) {
291: zend_uchar *to= *row;
292:
293: t.time_type= MYSQLND_TIMESTAMP_DATE;
294: t.neg= 0;
295:
296: t.second_part = t.hour = t.minute = t.second = 0;
297:
298: t.year = (unsigned int) sint2korr(to);
299: t.month = (unsigned int) to[2];
300: t.day = (unsigned int) to[3];
301:
302: (*row)+= length;
303: } else {
304: memset(&t, 0, sizeof(t));
305: t.time_type = MYSQLND_TIMESTAMP_DATE;
306: }
307:
1.1.1.2 ! misho 308: length = mnd_sprintf(&value, 0, "%04u-%02u-%02u", t.year, t.month, t.day);
1.1 misho 309:
310: DBG_INF_FMT("%s", value);
311: #if MYSQLND_UNICODE
312: if (!as_unicode) {
313: #endif
314: ZVAL_STRINGL(zv, value, length, 1);
1.1.1.2 ! misho 315: mnd_sprintf_free(value);
1.1 misho 316: #if MYSQLND_UNICODE
317: } else {
318: ZVAL_UTF8_STRINGL(zv, value, length, ZSTR_AUTOFREE);
319: }
320: #endif
321: DBG_VOID_RETURN;
322: }
323: /* }}} */
324:
325:
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)
331: {
332: struct st_mysqlnd_time t;
333: unsigned int length; /* First byte encodes the length*/
334: char * value;
335: DBG_ENTER("ps_fetch_datetime");
336:
337: if ((length = php_mysqlnd_net_field_length(row))) {
338: zend_uchar *to= *row;
339:
340: t.time_type = MYSQLND_TIMESTAMP_DATETIME;
341: t.neg = 0;
342:
343: t.year = (unsigned int) sint2korr(to);
344: t.month = (unsigned int) to[2];
345: t.day = (unsigned int) to[3];
346:
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;
353: }
354: t.second_part = (length > 7) ? (unsigned long) sint4korr(to+7) : 0;
355:
356: (*row)+= length;
357: } else {
358: memset(&t, 0, sizeof(t));
359: t.time_type = MYSQLND_TIMESTAMP_DATETIME;
360: }
361:
1.1.1.2 ! misho 362: length = mnd_sprintf(&value, 0, "%04u-%02u-%02u %02u:%02u:%02u", t.year, t.month, t.day, t.hour, t.minute, t.second);
1.1 misho 363:
364: DBG_INF_FMT("%s", value);
365: #if MYSQLND_UNICODE
366: if (!as_unicode) {
367: #endif
368: ZVAL_STRINGL(zv, value, length, 1);
1.1.1.2 ! misho 369: mnd_sprintf_free(value);
1.1 misho 370: #if MYSQLND_UNICODE
371: } else {
372: ZVAL_UTF8_STRINGL(zv, to, length, ZSTR_AUTOFREE);
373: }
374: #endif
375: DBG_VOID_RETURN;
376: }
377: /* }}} */
378:
379:
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)
385: {
386: /*
387: For now just copy, before we make it possible
388: to write \0 to the row buffer
389: */
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);
400: }
401: #else
402: DBG_INF("copying from the row buffer");
403: ZVAL_STRINGL(zv, (char *)*row, length, 1);
404: #endif
405:
406: (*row) += length;
407: DBG_VOID_RETURN;
408: }
409: /* }}} */
410:
411:
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)
417: {
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);
420: }
421: /* }}} */
422:
423:
424: /* {{{ _mysqlnd_init_ps_fetch_subsystem */
425: void _mysqlnd_init_ps_fetch_subsystem()
426: {
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;
432:
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;
437:
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;
442:
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;
447:
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;
452:
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;
457:
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;
462:
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;
467:
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;
472:
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;
477:
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;
482:
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;
487:
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;
492:
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;
497:
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;
503:
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;
509:
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;
515:
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;
521:
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;
526:
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;
531:
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;
536:
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;
541:
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;
546:
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;
551:
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;
555:
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;
559:
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;
563: }
564: /* }}} */
565:
566:
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)
570: {
571: if (!*copies) {
572: *copies = mnd_ecalloc(param_count, sizeof(zval *));
573: }
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;
580: }
581: return FAIL;
582: }
583: /* }}} */
584:
585:
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)
589: {
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;
599:
600: DBG_ENTER("mysqlnd_stmt_execute_store_params");
601:
602: {
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) {
1.1.1.2 ! misho 611: SET_OOM_ERROR(*stmt->error_info);
1.1 misho 612: goto end;
613: }
614: memcpy(tmp_buf, *buf, offset);
615: if (*buf != provided_buffer) {
616: mnd_efree(*buf);
617: }
618: *buf = tmp_buf;
619:
620: /* Update our pos pointer */
621: *p = *buf + offset;
622: }
623: /* put `null` bytes */
624: null_byte_offset = *p - *buf;
625: memset(*p, 0, null_count);
626: *p += null_count;
627: }
628:
629: /* 1. Store type information */
630: /*
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.
636: */
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))
640: {
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))
644: {
1.1.1.2 ! misho 645: SET_OOM_ERROR(*stmt->error_info);
1.1 misho 646: goto end;
647: }
648: /*
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
651: */
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;
657: }
658: }
659: }
660: }
661:
662: int1store(*p, stmt->send_types_to_server);
663: (*p)++;
664:
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) {
1.1.1.2 ! misho 673: SET_OOM_ERROR(*stmt->error_info);
1.1 misho 674: goto end;
675: }
676: memcpy(tmp_buf, *buf, offset);
677: if (*buf != provided_buffer) {
678: mnd_efree(*buf);
679: }
680: *buf = tmp_buf;
681:
682: /* Update our pos pointer */
683: *p = *buf + offset;
684: }
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;
691: }
692: #endif
693: if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_NULL && (current_type == MYSQL_TYPE_LONG || current_type == MYSQL_TYPE_LONGLONG)) {
694: /*
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
697: */
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;
700:
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;
705: /*
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.
710: */
711: } else {
712: convert_to_long_ex(&tmp_data);
713: }
714: }
715: }
716: int2store(*p, current_type);
717: *p+= 2;
718: }
719: }
720: stmt->send_types_to_server = resend_types_next_time;
721:
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;
727:
728: if (!the_var || (stmt->param_bind[i].type != MYSQL_TYPE_LONG_BLOB && Z_TYPE_P(the_var) == IS_NULL)) {
729: continue;
730: }
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)) {
1.1.1.2 ! misho 736: SET_OOM_ERROR(*stmt->error_info);
1.1 misho 737: goto end;
738: }
739: }
740: break;
741: }
742: }
743:
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)) {
1.1.1.2 ! misho 750: SET_OOM_ERROR(*stmt->error_info);
1.1 misho 751: goto end;
752: }
753: }
754: }
755: break;
756: case MYSQL_TYPE_LONGLONG:
757: {
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;
761: }
762: convert_to_long_ex(&tmp_data);
763: }
764: data_size += 8;
765: break;
766: case MYSQL_TYPE_LONG:
767: {
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;
771: }
772: convert_to_long_ex(&tmp_data);
773: }
774: data_size += 4;
775: break;
776: case MYSQL_TYPE_LONG_BLOB:
777: if (!(stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED)) {
778: /*
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.
782: */
783: data_size++;
784: }
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
794: {
795: if (!copies || !copies[i]) {
796: if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) {
1.1.1.2 ! misho 797: SET_OOM_ERROR(*stmt->error_info);
1.1 misho 798: goto end;
799: }
800: }
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);
805: }
806: #endif
807: }
808: convert_to_string_ex(&the_var);
809: data_size += Z_STRLEN_P(the_var);
810: break;
811: }
812: }
813:
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) {
1.1.1.2 ! misho 822: SET_OOM_ERROR(*stmt->error_info);
1.1 misho 823: goto end;
824: }
825: memcpy(tmp_buf, *buf, offset);
826: /*
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.
830: */
831: if (*buf != provided_buffer) {
832: mnd_efree(*buf);
833: }
834: *buf = tmp_buf;
835: /* Update our pos pointer */
836: *p = *buf + offset;
837: }
838:
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;
855: }
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;
863: }
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);
874: }
875: break;
876: case MYSQL_TYPE_VAR_STRING:
877: send_string:
878: {
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;
884: }
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;
890: }
891: }
892: }
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]);
899: }
900: }
901: mnd_efree(copies);
902: }
903:
904: DBG_INF_FMT("ret=%s", ret == PASS? "PASS":"FAIL");
905: DBG_RETURN(ret);
906: }
907: /* }}} */
908:
909:
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)
913: {
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;
919:
920: DBG_ENTER("mysqlnd_stmt_execute_generate_request");
921:
922: int4store(p, stmt->stmt_id);
923: p += 4;
924:
925: /* flags is 4 bytes, we store just 1 */
926: int1store(p, (zend_uchar) stmt->flags);
927: p++;
928:
929: /* Make it all zero */
930: int4store(p, 0);
931:
932: int1store(p, 1); /* and send 1 for iteration count */
933: p+= 4;
934:
935: ret = mysqlnd_stmt_execute_store_params(s, &cmd_buffer, &p, &cmd_buffer_length TSRMLS_CC);
936:
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);
942: }
943: /* }}} */
944:
945: /*
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
952: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>