1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 2006-2009 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: Georg Richter <georg@mysql.com> |
16 : | Andrey Hristov <andrey@mysql.com> |
17 : | Ulf Wendel <uwendel@mysql.com> |
18 : +----------------------------------------------------------------------+
19 : */
20 :
21 : /* $Id: mysqlnd_ps_codec.c 289030 2009-09-30 23:34:56Z andrey $ */
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 9020 : {
60 : char tmp[22];
61 9020 : size_t tmp_len = 0;
62 9020 : zend_bool is_bit = field->type == MYSQL_TYPE_BIT;
63 9020 : DBG_ENTER("ps_fetch_from_1_to_8_bytes");
64 9020 : DBG_INF_FMT("zv=%p byte_count=%d", zv, byte_count);
65 9020 : if (field->flags & UNSIGNED_FLAG) {
66 3568 : uint64_t uval = 0;
67 :
68 3568 : switch (byte_count) {
69 1529 : case 8:uval = is_bit? (uint64_t) bit_uint8korr(*row):(uint64_t) uint8korr(*row);break;
70 0 : case 7:uval = bit_uint7korr(*row);break;
71 180 : case 6:uval = bit_uint6korr(*row);break;
72 240 : case 5:uval = bit_uint5korr(*row);break;
73 422 : case 4:uval = is_bit? (uint64_t) bit_uint4korr(*row):(uint64_t) uint4korr(*row);break;
74 400 : case 3:uval = is_bit? (uint64_t) bit_uint3korr(*row):(uint64_t) uint3korr(*row);break;
75 434 : case 2:uval = is_bit? (uint64_t) bit_uint2korr(*row):(uint64_t) uint2korr(*row);break;
76 363 : case 1:uval = (uint64_t) uint1korr(*row);break;
77 : }
78 :
79 : #if SIZEOF_LONG==4
80 3568 : if (uval > INT_MAX) {
81 632 : DBG_INF("stringify");
82 632 : tmp_len = sprintf((char *)&tmp, MYSQLND_LLU_SPEC, uval);
83 : } else
84 : #endif /* #if SIZEOF_LONG==4 */
85 : {
86 5872 : if (byte_count < 8 || uval <= L64(9223372036854775807)) {
87 2936 : ZVAL_LONG(zv, uval);
88 : } else {
89 0 : DBG_INF("stringify");
90 0 : tmp_len = sprintf((char *)&tmp, MYSQLND_LLU_SPEC, uval);
91 : }
92 : }
93 : } else {
94 : /* SIGNED */
95 5452 : int64_t lval = 0;
96 5452 : switch (byte_count) {
97 520 : 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 4864 : case 4:lval = (int64_t) sint4korr(*row);break;
103 0 : case 3:lval = (int64_t) sint3korr(*row);break;
104 25 : case 2:lval = (int64_t) sint2korr(*row);break;
105 43 : case 1:lval = (int64_t) *(int8_t*)*row;break;
106 : }
107 :
108 : #if SIZEOF_LONG==4
109 5587 : if ((L64(2147483647) < (int64_t) lval) || (L64(-2147483648) > (int64_t) lval)) {
110 135 : DBG_INF("stringify");
111 135 : tmp_len = sprintf((char *)&tmp, MYSQLND_LL_SPEC, lval);
112 : } else
113 : #endif /* SIZEOF */
114 : {
115 5317 : ZVAL_LONG(zv, lval);
116 : }
117 : }
118 :
119 9020 : if (tmp_len) {
120 : #if PHP_MAJOR_VERSION >= 6
121 767 : if (as_unicode) {
122 767 : DBG_INF("stringify");
123 767 : ZVAL_UTF8_STRINGL(zv, tmp, tmp_len, ZSTR_DUPLICATE);
124 : } else
125 : #endif
126 : {
127 0 : DBG_INF("stringify");
128 0 : ZVAL_STRINGL(zv, tmp, tmp_len, 1);
129 : }
130 : }
131 9020 : (*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 0 : {
143 0 : ZVAL_NULL(zv);
144 0 : }
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 57 : {
154 57 : ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, 1 TSRMLS_CC);
155 57 : }
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 59 : {
165 59 : ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, 2 TSRMLS_CC);
166 59 : }
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 4906 : {
176 4906 : ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, 4 TSRMLS_CC);
177 4906 : }
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 2049 : {
187 2049 : ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, 8 TSRMLS_CC);
188 2049 : }
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 114 : {
198 : float value;
199 114 : DBG_ENTER("ps_fetch_float");
200 114 : float4get(value, *row);
201 114 : ZVAL_DOUBLE(zv, value);
202 114 : (*row)+= 4;
203 114 : 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 50 : {
215 : double value;
216 50 : DBG_ENTER("ps_fetch_double");
217 50 : float8get(value, *row);
218 50 : ZVAL_DOUBLE(zv, value);
219 50 : (*row)+= 8;
220 50 : 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 20 : {
232 : struct st_mysqlnd_time t;
233 : unsigned int length; /* First byte encodes the length*/
234 : char *to;
235 20 : DBG_ENTER("ps_fetch_time");
236 :
237 20 : if ((length = php_mysqlnd_net_field_length(row))) {
238 20 : zend_uchar *to= *row;
239 :
240 20 : t.time_type = MYSQLND_TIMESTAMP_TIME;
241 20 : t.neg = (zend_bool) to[0];
242 :
243 20 : t.day = (unsigned long) sint4korr(to+1);
244 20 : t.hour = (unsigned int) to[5];
245 20 : t.minute = (unsigned int) to[6];
246 20 : t.second = (unsigned int) to[7];
247 20 : t.second_part = (length > 8) ? (unsigned long) sint4korr(to+8) : 0;
248 20 : t.year = t.month= 0;
249 20 : if (t.day) {
250 : /* Convert days to hours at once */
251 0 : t.hour += t.day*24;
252 0 : t.day = 0;
253 : }
254 :
255 20 : (*row) += length;
256 : } else {
257 0 : memset(&t, 0, sizeof(t));
258 0 : t.time_type = MYSQLND_TIMESTAMP_TIME;
259 : }
260 :
261 : /*
262 : QQ : How to make this unicode without copying two times the buffer -
263 : Unicode equivalent of spprintf?
264 : */
265 20 : length = spprintf(&to, 0, "%s%02u:%02u:%02u",
266 : (t.neg ? "-" : ""), t.hour, t.minute, t.second);
267 :
268 20 : DBG_INF_FMT("%s", to);
269 : #if PHP_MAJOR_VERSION >= 6
270 20 : if (!as_unicode) {
271 : #endif
272 1 : ZVAL_STRINGL(zv, to, length, 1);
273 1 : mnd_efree(to);
274 : #if PHP_MAJOR_VERSION >= 6
275 : } else {
276 19 : ZVAL_UTF8_STRINGL(zv, to, length, ZSTR_AUTOFREE);
277 : }
278 : #endif
279 : DBG_VOID_RETURN;
280 : }
281 : /* }}} */
282 :
283 :
284 : /* {{{ ps_fetch_date */
285 : static
286 : void ps_fetch_date(zval *zv, const MYSQLND_FIELD * const field,
287 : unsigned int pack_len, zend_uchar **row,
288 : zend_bool as_unicode TSRMLS_DC)
289 20 : {
290 20 : struct st_mysqlnd_time t = {0};
291 : unsigned int length; /* First byte encodes the length*/
292 : char *to;
293 20 : DBG_ENTER("ps_fetch_date");
294 :
295 20 : if ((length = php_mysqlnd_net_field_length(row))) {
296 20 : zend_uchar *to= *row;
297 :
298 20 : t.time_type= MYSQLND_TIMESTAMP_DATE;
299 20 : t.neg= 0;
300 :
301 20 : t.second_part = t.hour = t.minute = t.second = 0;
302 :
303 20 : t.year = (unsigned int) sint2korr(to);
304 20 : t.month = (unsigned int) to[2];
305 20 : t.day = (unsigned int) to[3];
306 :
307 20 : (*row)+= length;
308 : } else {
309 0 : memset(&t, 0, sizeof(t));
310 0 : t.time_type = MYSQLND_TIMESTAMP_DATE;
311 : }
312 :
313 : /*
314 : QQ : How to make this unicode without copying two times the buffer -
315 : Unicode equivalent of spprintf?
316 : */
317 20 : length = spprintf(&to, 0, "%04u-%02u-%02u", t.year, t.month, t.day);
318 :
319 20 : DBG_INF_FMT("%s", to);
320 : #if PHP_MAJOR_VERSION >= 6
321 20 : if (!as_unicode) {
322 : #endif
323 1 : ZVAL_STRINGL(zv, to, length, 1);
324 1 : mnd_efree(to);
325 : #if PHP_MAJOR_VERSION >= 6
326 : } else {
327 19 : ZVAL_UTF8_STRINGL(zv, to, length, ZSTR_AUTOFREE);
328 : }
329 : #endif
330 : DBG_VOID_RETURN;
331 : }
332 : /* }}} */
333 :
334 :
335 : /* {{{ ps_fetch_datetime */
336 : static
337 : void ps_fetch_datetime(zval *zv, const MYSQLND_FIELD * const field,
338 : unsigned int pack_len, zend_uchar **row,
339 : zend_bool as_unicode TSRMLS_DC)
340 38 : {
341 : struct st_mysqlnd_time t;
342 : unsigned int length; /* First byte encodes the length*/
343 : char *to;
344 38 : DBG_ENTER("ps_fetch_datetime");
345 :
346 38 : if ((length = php_mysqlnd_net_field_length(row))) {
347 35 : zend_uchar *to= *row;
348 :
349 35 : t.time_type = MYSQLND_TIMESTAMP_DATETIME;
350 35 : t.neg = 0;
351 :
352 35 : t.year = (unsigned int) sint2korr(to);
353 35 : t.month = (unsigned int) to[2];
354 35 : t.day = (unsigned int) to[3];
355 :
356 35 : if (length > 4) {
357 31 : t.hour = (unsigned int) to[4];
358 31 : t.minute = (unsigned int) to[5];
359 31 : t.second = (unsigned int) to[6];
360 : } else {
361 4 : t.hour = t.minute = t.second= 0;
362 : }
363 35 : t.second_part = (length > 7) ? (unsigned long) sint4korr(to+7) : 0;
364 :
365 35 : (*row)+= length;
366 : } else {
367 3 : memset(&t, 0, sizeof(t));
368 3 : t.time_type = MYSQLND_TIMESTAMP_DATETIME;
369 : }
370 :
371 : /*
372 : QQ : How to make this unicode without copying two times the buffer -
373 : Unicode equivalent of spprintf?
374 : */
375 38 : length = spprintf(&to, 0, "%04u-%02u-%02u %02u:%02u:%02u",
376 : t.year, t.month, t.day, t.hour, t.minute, t.second);
377 :
378 38 : DBG_INF_FMT("%s", to);
379 : #if PHP_MAJOR_VERSION >= 6
380 38 : if (!as_unicode) {
381 : #endif
382 2 : ZVAL_STRINGL(zv, to, length, 1);
383 2 : mnd_efree(to);
384 : #if PHP_MAJOR_VERSION >= 6
385 : } else {
386 36 : ZVAL_UTF8_STRINGL(zv, to, length, ZSTR_AUTOFREE);
387 : }
388 : #endif
389 : DBG_VOID_RETURN;
390 : }
391 : /* }}} */
392 :
393 :
394 : /* {{{ ps_fetch_string */
395 : static
396 : void ps_fetch_string(zval *zv, const MYSQLND_FIELD * const field,
397 : unsigned int pack_len, zend_uchar **row,
398 : zend_bool as_unicode TSRMLS_DC)
399 5845 : {
400 : /*
401 : For now just copy, before we make it possible
402 : to write \0 to the row buffer
403 : */
404 5845 : unsigned long length = php_mysqlnd_net_field_length(row);
405 5845 : DBG_ENTER("ps_fetch_string");
406 5845 : DBG_INF_FMT("len = %lu", length);
407 : #if PHP_MAJOR_VERSION < 6
408 : DBG_INF("copying from the row buffer");
409 : ZVAL_STRINGL(zv, (char *)*row, length, 1);
410 : #else
411 5845 : if (field->charsetnr == MYSQLND_BINARY_CHARSET_NR) {
412 1199 : DBG_INF("Binary charset");
413 1199 : ZVAL_STRINGL(zv, (char *)*row, length, 1);
414 : } else {
415 4646 : DBG_INF_FMT("copying from the row buffer");
416 4646 : ZVAL_UTF8_STRINGL(zv, (char*)*row, length, ZSTR_DUPLICATE);
417 : }
418 : #endif
419 :
420 5845 : (*row) += length;
421 : DBG_VOID_RETURN;
422 : }
423 : /* }}} */
424 :
425 :
426 : /* {{{ ps_fetch_bit */
427 : static
428 : void ps_fetch_bit(zval *zv, const MYSQLND_FIELD * const field,
429 : unsigned int pack_len, zend_uchar **row,
430 : zend_bool as_unicode TSRMLS_DC)
431 1487 : {
432 1487 : unsigned long length= php_mysqlnd_net_field_length(row);
433 1487 : ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, length TSRMLS_CC);
434 1487 : }
435 : /* }}} */
436 :
437 :
438 : /* {{{ _mysqlnd_init_ps_fetch_subsystem */
439 : void _mysqlnd_init_ps_fetch_subsystem()
440 17007 : {
441 17007 : memset(mysqlnd_ps_fetch_functions, 0, sizeof(mysqlnd_ps_fetch_functions));
442 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].func = ps_fetch_null;
443 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].pack_len = 0;
444 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].php_type = IS_NULL;
445 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].can_ret_as_str_in_uni = TRUE;
446 :
447 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].func = ps_fetch_int8;
448 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].pack_len = 1;
449 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].php_type = IS_LONG;
450 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].can_ret_as_str_in_uni = TRUE;
451 :
452 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].func = ps_fetch_int16;
453 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].pack_len = 2;
454 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].php_type = IS_LONG;
455 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].can_ret_as_str_in_uni = TRUE;
456 :
457 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].func = ps_fetch_int16;
458 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].pack_len = 2;
459 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].php_type = IS_LONG;
460 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].can_ret_as_str_in_uni = TRUE;
461 :
462 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].func = ps_fetch_int32;
463 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].pack_len = 4;
464 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].php_type = IS_LONG;
465 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].can_ret_as_str_in_uni = TRUE;
466 :
467 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].func = ps_fetch_int32;
468 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].pack_len = 4;
469 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].php_type = IS_LONG;
470 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].can_ret_as_str_in_uni = TRUE;
471 :
472 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].func = ps_fetch_int64;
473 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].pack_len= 8;
474 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].php_type = IS_LONG;
475 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].can_ret_as_str_in_uni = TRUE;
476 :
477 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].func = ps_fetch_float;
478 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].pack_len = 4;
479 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].php_type = IS_DOUBLE;
480 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].can_ret_as_str_in_uni = TRUE;
481 :
482 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].func = ps_fetch_double;
483 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].pack_len = 8;
484 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].php_type = IS_DOUBLE;
485 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].can_ret_as_str_in_uni = TRUE;
486 :
487 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].func = ps_fetch_time;
488 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].pack_len = MYSQLND_PS_SKIP_RESULT_W_LEN;
489 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].php_type = IS_STRING;
490 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].can_ret_as_str_in_uni = TRUE;
491 :
492 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].func = ps_fetch_date;
493 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].pack_len = MYSQLND_PS_SKIP_RESULT_W_LEN;
494 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].php_type = IS_STRING;
495 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].can_ret_as_str_in_uni = TRUE;
496 :
497 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].func = ps_fetch_date;
498 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].pack_len = MYSQLND_PS_SKIP_RESULT_W_LEN;
499 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].php_type = IS_STRING;
500 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].can_ret_as_str_in_uni = TRUE;
501 :
502 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].func = ps_fetch_datetime;
503 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].pack_len= MYSQLND_PS_SKIP_RESULT_W_LEN;
504 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].php_type= IS_STRING;
505 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].can_ret_as_str_in_uni = TRUE;
506 :
507 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].func = ps_fetch_datetime;
508 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].pack_len= MYSQLND_PS_SKIP_RESULT_W_LEN;
509 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].php_type= IS_STRING;
510 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].can_ret_as_str_in_uni = TRUE;
511 :
512 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].func = ps_fetch_string;
513 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].pack_len= MYSQLND_PS_SKIP_RESULT_STR;
514 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].php_type = IS_STRING;
515 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].is_possibly_blob = TRUE;
516 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].can_ret_as_str_in_uni = TRUE;
517 :
518 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].func = ps_fetch_string;
519 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
520 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].php_type = IS_STRING;
521 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].is_possibly_blob = TRUE;
522 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].can_ret_as_str_in_uni = TRUE;
523 :
524 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].func = ps_fetch_string;
525 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].pack_len= MYSQLND_PS_SKIP_RESULT_STR;
526 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].php_type= IS_STRING;
527 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].is_possibly_blob = TRUE;
528 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].can_ret_as_str_in_uni = TRUE;
529 :
530 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].func = ps_fetch_string;
531 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
532 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].php_type = IS_STRING;
533 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].is_possibly_blob = TRUE;
534 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].can_ret_as_str_in_uni = TRUE;
535 :
536 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].func = ps_fetch_bit;
537 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].pack_len = 8;
538 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].php_type = IS_LONG;
539 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].can_ret_as_str_in_uni = TRUE;
540 :
541 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].func = ps_fetch_string;
542 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
543 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].php_type = IS_STRING;
544 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].is_possibly_blob = TRUE;
545 :
546 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].func = ps_fetch_string;
547 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
548 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].php_type = IS_STRING;
549 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].is_possibly_blob = TRUE;
550 :
551 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].func = ps_fetch_string;
552 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
553 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].php_type = IS_STRING;
554 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].is_possibly_blob = TRUE;
555 :
556 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].func = ps_fetch_string;
557 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
558 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].php_type = IS_STRING;
559 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].can_ret_as_str_in_uni = TRUE;
560 :
561 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].func = ps_fetch_string;
562 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
563 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].php_type = IS_STRING;
564 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].can_ret_as_str_in_uni = TRUE;
565 :
566 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_ENUM].func = ps_fetch_string;
567 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_ENUM].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
568 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_ENUM].php_type = IS_STRING;
569 :
570 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_SET].func = ps_fetch_string;
571 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_SET].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
572 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_SET].php_type = IS_STRING;
573 :
574 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].func = ps_fetch_string;
575 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].pack_len= MYSQLND_PS_SKIP_RESULT_STR;
576 17007 : mysqlnd_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].php_type= IS_STRING;
577 17007 : }
578 : /* }}} */
579 :
580 :
581 : /* {{{ mysqlnd_stmt_copy_it */
582 : static void
583 : mysqlnd_stmt_copy_it(zval *** copies, zval *original, unsigned int param_count, unsigned int current TSRMLS_DC)
584 1146 : {
585 1146 : if (!*copies) {
586 780 : *copies = mnd_ecalloc(param_count, sizeof(zval *));
587 : }
588 1146 : MAKE_STD_ZVAL((*copies)[current]);
589 1146 : *(*copies)[current] = *original;
590 1146 : Z_SET_REFCOUNT_P((*copies)[current], 1);
591 1146 : zval_copy_ctor((*copies)[current]);
592 1146 : }
593 : /* }}} */
594 :
595 :
596 : /* {{{ mysqlnd_stmt_execute_store_params */
597 : static void
598 : mysqlnd_stmt_execute_store_params(MYSQLND_STMT *stmt, zend_uchar **buf, zend_uchar **p,
599 : size_t *buf_len, unsigned int null_byte_offset TSRMLS_DC)
600 4764 : {
601 4764 : unsigned int i = 0;
602 4764 : size_t left = (*buf_len - (*p - *buf));
603 4764 : size_t data_size = 0;
604 4764 : zval **copies = NULL;/* if there are different types */
605 :
606 : /* 1. Store type information */
607 4764 : if (stmt->send_types_to_server) {
608 :
609 : /* 2 bytes per type, and leave 20 bytes for future use */
610 1024 : if (left < ((stmt->param_count * 2) + 20)) {
611 0 : unsigned int offset = *p - *buf;
612 : zend_uchar *tmp_buf;
613 0 : *buf_len = offset + stmt->param_count * 2 + 20;
614 0 : tmp_buf = mnd_emalloc(*buf_len);
615 0 : memcpy(tmp_buf, *buf, offset);
616 0 : *buf = tmp_buf;
617 :
618 : /* Update our pos pointer */
619 0 : *p = *buf + offset;
620 : }
621 2990 : for (i = 0; i < stmt->param_count; i++) {
622 : /* our types are not unsigned */
623 : #if SIZEOF_LONG==8
624 : if (stmt->param_bind[i].type == MYSQL_TYPE_LONG) {
625 : stmt->param_bind[i].type = MYSQL_TYPE_LONGLONG;
626 : }
627 : #endif
628 1966 : int2store(*p, stmt->param_bind[i].type);
629 1966 : *p+= 2;
630 : }
631 : }
632 :
633 : /* 2. Store data */
634 : /* 2.1 Calculate how much space we need */
635 7467 : for (i = 0; i < stmt->param_count; i++) {
636 : unsigned int j;
637 2703 : zval *the_var = stmt->param_bind[i].zv;
638 :
639 2703 : if (!the_var || (stmt->param_bind[i].type != MYSQL_TYPE_LONG_BLOB &&
640 : Z_TYPE_P(the_var) == IS_NULL)) {
641 : continue;
642 : }
643 3386 : for (j = i + 1; j < stmt->param_count; j++) {
644 1378 : if (stmt->param_bind[j].zv == the_var) {
645 : /* Double binding of the same zval, make a copy */
646 474 : mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC);
647 474 : break;
648 : }
649 : }
650 :
651 2482 : switch (stmt->param_bind[i].type) {
652 : case MYSQL_TYPE_DOUBLE:
653 992 : data_size += 8;
654 992 : if (Z_TYPE_P(the_var) != IS_DOUBLE) {
655 722 : if (!copies || !copies[i]) {
656 384 : mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC);
657 : }
658 : }
659 992 : break;
660 : #if SIZEOF_LONG==8
661 : case MYSQL_TYPE_LONGLONG:
662 : data_size += 8;
663 : #elif SIZEOF_LONG==4
664 : case MYSQL_TYPE_LONG:
665 877 : data_size += 4;
666 : #else
667 : #error "Should not happen"
668 : #endif
669 877 : if (Z_TYPE_P(the_var) != IS_LONG) {
670 13 : if (!copies || !copies[i]) {
671 11 : mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC);
672 : }
673 : }
674 877 : break;
675 : case MYSQL_TYPE_LONG_BLOB:
676 48 : if (!(stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED)) {
677 : /*
678 : User hasn't sent anything, we will send empty string.
679 : Empty string has length of 0, encoded in 1 byte. No real
680 : data will follows after it.
681 : */
682 45 : data_size++;
683 : }
684 48 : break;
685 : case MYSQL_TYPE_VAR_STRING:
686 565 : data_size += 8; /* max 8 bytes for size */
687 : #if PHP_MAJOR_VERSION < 6
688 : if (Z_TYPE_P(the_var) != IS_STRING)
689 : #elif PHP_MAJOR_VERSION >= 6
690 565 : if (Z_TYPE_P(the_var) != IS_STRING || Z_TYPE_P(the_var) == IS_UNICODE)
691 : #endif
692 : {
693 280 : if (!copies || !copies[i]) {
694 277 : mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC);
695 : }
696 280 : the_var = copies[i];
697 : #if PHP_MAJOR_VERSION >= 6
698 280 : if (Z_TYPE_P(the_var) == IS_UNICODE) {
699 257 : zval_unicode_to_string_ex(the_var, UG(utf8_conv) TSRMLS_CC);
700 : }
701 : #endif
702 : }
703 565 : convert_to_string_ex(&the_var);
704 565 : data_size += Z_STRLEN_P(the_var);
705 : break;
706 : }
707 :
708 : }
709 :
710 : /* 2.2 Enlarge the buffer, if needed */
711 4764 : left = (*buf_len - (*p - *buf));
712 4764 : if (left < data_size) {
713 14 : unsigned int offset = *p - *buf;
714 : zend_uchar *tmp_buf;
715 14 : *buf_len = offset + data_size + 10; /* Allocate + 10 for safety */
716 14 : tmp_buf = mnd_emalloc(*buf_len);
717 14 : memcpy(tmp_buf, *buf, offset);
718 14 : *buf = tmp_buf;
719 : /* Update our pos pointer */
720 14 : *p = *buf + offset;
721 : }
722 :
723 : /* 2.3 Store the actual data */
724 7467 : for (i = 0; i < stmt->param_count; i++) {
725 2703 : zval *data = copies && copies[i]? copies[i]: stmt->param_bind[i].zv;
726 : /* Handle long data */
727 2929 : if (stmt->param_bind[i].zv && Z_TYPE_P(data) == IS_NULL) {
728 226 : (*buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7));
729 : } else {
730 2477 : switch (stmt->param_bind[i].type) {
731 : case MYSQL_TYPE_DOUBLE:
732 992 : convert_to_double_ex(&data);
733 992 : float8store(*p, Z_DVAL_P(data));
734 992 : (*p) += 8;
735 992 : break;
736 : #if SIZEOF_LONG==8
737 : case MYSQL_TYPE_LONGLONG:
738 : convert_to_long_ex(&data);
739 : int8store(*p, Z_LVAL_P(data));
740 : (*p) += 8;
741 : break;
742 : #elif SIZEOF_LONG==4
743 : case MYSQL_TYPE_LONG:
744 877 : convert_to_long_ex(&data);
745 877 : int4store(*p, Z_LVAL_P(data));
746 877 : (*p) += 4;
747 877 : break;
748 : #else
749 : #error "Should not happen"
750 : #endif
751 : case MYSQL_TYPE_LONG_BLOB:
752 43 : if (stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED) {
753 0 : stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
754 : } else {
755 : /* send_long_data() not called, send empty string */
756 43 : *p = php_mysqlnd_net_store_length(*p, 0);
757 : }
758 43 : break;
759 : case MYSQL_TYPE_VAR_STRING:{
760 565 : unsigned int len = Z_STRLEN_P(data);
761 : /* to is after p. The latter hasn't been moved */
762 565 : *p = php_mysqlnd_net_store_length(*p, len);
763 565 : memcpy(*p, Z_STRVAL_P(data), len);
764 565 : (*p) += len;
765 : }
766 565 : break;
767 : default:
768 : /* Won't happen, but set to NULL */
769 0 : (*buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7));
770 : break;
771 : }
772 : }
773 : }
774 4764 : if (copies) {
775 2345 : for (i = 0; i < stmt->param_count; i++) {
776 1565 : if (copies[i]) {
777 1146 : zval_ptr_dtor(&copies[i]);
778 : }
779 : }
780 780 : mnd_efree(copies);
781 : }
782 4764 : }
783 : /* }}} */
784 :
785 :
786 : /* {{{ mysqlnd_stmt_execute_generate_request */
787 : zend_uchar* mysqlnd_stmt_execute_generate_request(MYSQLND_STMT *stmt, size_t *request_len,
788 : zend_bool *free_buffer TSRMLS_DC)
789 4764 : {
790 4764 : zend_uchar *p = stmt->execute_cmd_buffer.buffer,
791 4764 : *cmd_buffer = stmt->execute_cmd_buffer.buffer;
792 4764 : size_t cmd_buffer_length = stmt->execute_cmd_buffer.length;
793 : unsigned int null_byte_offset,
794 4764 : null_count= (stmt->param_count + 7) / 8;
795 :
796 4764 : int4store(p, stmt->stmt_id);
797 4764 : p += 4;
798 :
799 : /* flags is 4 bytes, we store just 1 */
800 4764 : int1store(p, (zend_uchar) stmt->flags);
801 4764 : p++;
802 :
803 : /* Make it all zero */
804 4764 : int4store(p, 0);
805 :
806 4764 : int1store(p, 1); /* and send 1 for iteration count */
807 4764 : p+= 4;
808 :
809 :
810 4764 : null_byte_offset = p - cmd_buffer;
811 4764 : memset(p, 0, null_count);
812 4764 : p += null_count;
813 :
814 :
815 4764 : int1store(p, stmt->send_types_to_server);
816 4764 : p++;
817 :
818 4764 : mysqlnd_stmt_execute_store_params(stmt, &cmd_buffer, &p, &cmd_buffer_length, null_byte_offset TSRMLS_CC);
819 :
820 4764 : *free_buffer = (cmd_buffer != stmt->execute_cmd_buffer.buffer);
821 4764 : *request_len = (p - cmd_buffer);
822 4764 : return cmd_buffer;
823 : }
824 : /* }}} */
825 :
826 : /*
827 : * Local variables:
828 : * tab-width: 4
829 : * c-basic-offset: 4
830 : * End:
831 : * vim600: noet sw=4 ts=4 fdm=marker
832 : * vim<600: noet sw=4 ts=4
833 : */
|