php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
mysqlnd_ps_codec.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Andrey Hristov <andrey@php.net> |
14 | Ulf Wendel <uw@php.net> |
15 +----------------------------------------------------------------------+
16*/
17
18#include <math.h>
19#include "php.h"
20#include "mysqlnd.h"
22#include "mysqlnd_connection.h"
23#include "mysqlnd_ps.h"
24#include "mysqlnd_priv.h"
25#include "mysqlnd_debug.h"
27
28
37
38
46
47
49
50#define MYSQLND_PS_SKIP_RESULT_W_LEN -1
51#define MYSQLND_PS_SKIP_RESULT_STR -2
52
53static inline void ps_fetch_over_read_error(const zend_uchar ** row)
54{
55 php_error_docref(NULL, E_WARNING, "Malformed server packet. Field length pointing after the end of packet");
56 *row = NULL;
57}
58
59static inline bool ps_fetch_is_packet_over_read_with_variable_length(const unsigned int pack_len,
60 const zend_uchar ** row, const zend_uchar *p, unsigned int length)
61{
62 if (pack_len == 0) {
63 return false;
64 }
65 size_t length_len = *row - p;
66 if (length_len > pack_len || length > pack_len - length_len) {
67 ps_fetch_over_read_error(row);
68 return true;
69 }
70 return false;
71}
72
73static inline bool ps_fetch_is_packet_over_read_with_static_length(const unsigned int pack_len,
74 const zend_uchar ** row, unsigned int length)
75{
76 if (pack_len > 0 && length > pack_len) {
77 ps_fetch_over_read_error(row);
78 return true;
79 }
80 return false;
81}
82
83
84/* {{{ ps_fetch_from_1_to_8_bytes */
85void
86ps_fetch_from_1_to_8_bytes(zval * zv, const MYSQLND_FIELD * const field, const unsigned int pack_len,
87 const zend_uchar ** row, unsigned int byte_count)
88{
89 if (UNEXPECTED(ps_fetch_is_packet_over_read_with_static_length(pack_len, row, byte_count))) {
90 return;
91 }
92
93 bool is_bit = field->type == MYSQL_TYPE_BIT;
94 DBG_ENTER("ps_fetch_from_1_to_8_bytes");
95 DBG_INF_FMT("zv=%p byte_count=%u", zv, byte_count);
96 if (field->flags & UNSIGNED_FLAG) {
97 uint64_t uval = 0;
98
99 switch (byte_count) {
100 case 8:uval = is_bit? (uint64_t) bit_uint8korr(*row):(uint64_t) uint8korr(*row);break;
101 case 7:uval = bit_uint7korr(*row);break;
102 case 6:uval = bit_uint6korr(*row);break;
103 case 5:uval = bit_uint5korr(*row);break;
104 case 4:uval = is_bit? (uint64_t) bit_uint4korr(*row):(uint64_t) uint4korr(*row);break;
105 case 3:uval = is_bit? (uint64_t) bit_uint3korr(*row):(uint64_t) uint3korr(*row);break;
106 case 2:uval = is_bit? (uint64_t) bit_uint2korr(*row):(uint64_t) uint2korr(*row);break;
107 case 1:uval = (uint64_t) uint1korr(*row);break;
108 }
109
110 if (field->flags & ZEROFILL_FLAG) {
111 DBG_INF("stringify due to zerofill");
112 ZVAL_STR(zv, zend_strpprintf(0, "%0*" PRIu64, (int) field->length, uval));
113 } else
114#if SIZEOF_ZEND_LONG==4
115 if (uval > INT_MAX) {
116 DBG_INF("stringify");
118 } else
119#endif /* #if SIZEOF_LONG==4 */
120 {
121 if (byte_count < 8 || uval <= L64(9223372036854775807)) {
122 ZVAL_LONG(zv, (zend_long) uval); /* the cast is safe, we are in the range */
123 } else {
124 DBG_INF("stringify");
126 }
127 }
128 } else {
129 /* SIGNED */
130 int64_t lval = 0;
131 switch (byte_count) {
132 case 8:lval = (int64_t) sint8korr(*row);break;
133 /*
134 7, 6 and 5 are not possible.
135 BIT is only unsigned, thus only uint5|6|7 macros exist
136 */
137 case 4:lval = (int64_t) sint4korr(*row);break;
138 case 3:lval = (int64_t) sint3korr(*row);break;
139 case 2:lval = (int64_t) sint2korr(*row);break;
140 case 1:lval = (int64_t) *(int8_t*)*row;break;
141 }
142
143#if SIZEOF_ZEND_LONG==4
144 if ((L64(2147483647) < (int64_t) lval) || (L64(-2147483648) > (int64_t) lval)) {
145 DBG_INF("stringify");
147 } else
148#endif /* SIZEOF */
149 {
150 ZVAL_LONG(zv, (zend_long) lval); /* the cast is safe, we are in the range */
151 }
152 }
153
154 (*row)+= byte_count;
156}
157/* }}} */
158
159
160/* {{{ ps_fetch_null */
161static void
162ps_fetch_null(zval *zv, const MYSQLND_FIELD * const field, const unsigned int pack_len, const zend_uchar ** row)
163{
164 ZVAL_NULL(zv);
165}
166/* }}} */
167
168
169/* {{{ ps_fetch_int8 */
170static void
171ps_fetch_int8(zval * zv, const MYSQLND_FIELD * const field, const unsigned int pack_len, const zend_uchar ** row)
172{
173 ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, 1);
174}
175/* }}} */
176
177
178/* {{{ ps_fetch_int16 */
179static void
180ps_fetch_int16(zval * zv, const MYSQLND_FIELD * const field, const unsigned int pack_len, const zend_uchar ** row)
181{
182 ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, 2);
183}
184/* }}} */
185
186
187/* {{{ ps_fetch_int32 */
188static void
189ps_fetch_int32(zval * zv, const MYSQLND_FIELD * const field, const unsigned int pack_len, const zend_uchar ** row)
190{
191 ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, 4);
192}
193/* }}} */
194
195
196/* {{{ ps_fetch_int64 */
197static void
198ps_fetch_int64(zval * zv, const MYSQLND_FIELD * const field, const unsigned int pack_len, const zend_uchar ** row)
199{
200 ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, 8);
201}
202/* }}} */
203
204
205/* {{{ ps_fetch_float */
206static void
207ps_fetch_float(zval * zv, const MYSQLND_FIELD * const field, const unsigned int pack_len, const zend_uchar ** row)
208{
209 float fval;
210 double dval;
211 DBG_ENTER("ps_fetch_float");
212
213 if (UNEXPECTED(ps_fetch_is_packet_over_read_with_static_length(pack_len, row, 4))) {
214 return;
215 }
216
217 float4get(fval, *row);
218 (*row)+= 4;
219 DBG_INF_FMT("value=%f", fval);
220
221#ifndef NOT_FIXED_DEC
222# define NOT_FIXED_DEC 31
223#endif
224
225 dval = mysql_float_to_double(fval, (field->decimals >= NOT_FIXED_DEC) ? -1 : (int)field->decimals);
226
229}
230/* }}} */
231
232
233/* {{{ ps_fetch_double */
234static void
235ps_fetch_double(zval * zv, const MYSQLND_FIELD * const field, const unsigned int pack_len, const zend_uchar ** row)
236{
237 double value;
238 DBG_ENTER("ps_fetch_double");
239
240 if (UNEXPECTED(ps_fetch_is_packet_over_read_with_static_length(pack_len, row, 8))) {
241 return;
242 }
243
244 float8get(value, *row);
246 (*row)+= 8;
247 DBG_INF_FMT("value=%f", value);
249}
250/* }}} */
251
252
253/* {{{ ps_fetch_time */
254static void
255ps_fetch_time(zval * zv, const MYSQLND_FIELD * const field, const unsigned int pack_len, const zend_uchar ** row)
256{
257 struct st_mysqlnd_time t;
258 zend_ulong length; /* First byte encodes the length */
259 const zend_uchar *p = *row;
260 DBG_ENTER("ps_fetch_time");
261
262 if ((length = php_mysqlnd_net_field_length(row))) {
263 if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) {
264 return;
265 }
266
267 const zend_uchar * to = *row;
268
269 t.time_type = MYSQLND_TIMESTAMP_TIME;
270 t.neg = (bool) to[0];
271
272 t.day = (zend_ulong) sint4korr(to+1);
273 t.hour = (unsigned int) to[5];
274 t.minute = (unsigned int) to[6];
275 t.second = (unsigned int) to[7];
276 t.second_part = (length > 8) ? (zend_ulong) sint4korr(to+8) : 0;
277 t.year = t.month= 0;
278 if (t.day) {
279 /* Convert days to hours at once */
280 t.hour += t.day*24;
281 t.day = 0;
282 }
283
284 (*row) += length;
285 } else {
286 memset(&t, 0, sizeof(t));
287 t.time_type = MYSQLND_TIMESTAMP_TIME;
288 }
289
290 if (field->decimals > 0 && field->decimals < 7) {
291 ZVAL_STR(zv, zend_strpprintf(0, "%s%02u:%02u:%02u.%0*u",
292 (t.neg ? "-" : ""), t.hour, t.minute, t.second, field->decimals,
293 (uint32_t) (t.second_part / pow(10, 6 - field->decimals))));
294 } else {
295 ZVAL_STR(zv, zend_strpprintf(0, "%s%02u:%02u:%02u",
296 (t.neg ? "-" : ""), t.hour, t.minute, t.second));
297 }
299}
300/* }}} */
301
302
303/* {{{ ps_fetch_date */
304static void
305ps_fetch_date(zval * zv, const MYSQLND_FIELD * const field, const unsigned int pack_len, const zend_uchar ** row)
306{
307 struct st_mysqlnd_time t = {0};
308 zend_ulong length; /* First byte encodes the length*/
309 const zend_uchar *p = *row;
310 DBG_ENTER("ps_fetch_date");
311
312 if ((length = php_mysqlnd_net_field_length(row))) {
313 if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) {
314 return;
315 }
316
317 const zend_uchar * to = *row;
318
320 t.neg = 0;
321
322 t.second_part = t.hour = t.minute = t.second = 0;
323
324 t.year = (unsigned int) sint2korr(to);
325 t.month = (unsigned int) to[2];
326 t.day = (unsigned int) to[3];
327
328 (*row)+= length;
329 } else {
330 memset(&t, 0, sizeof(t));
332 }
333
334 ZVAL_STR(zv, zend_strpprintf(0, "%04u-%02u-%02u", t.year, t.month, t.day));
336}
337/* }}} */
338
339
340/* {{{ ps_fetch_datetime */
341static void
342ps_fetch_datetime(zval * zv, const MYSQLND_FIELD * const field, const unsigned int pack_len, const zend_uchar ** row)
343{
344 struct st_mysqlnd_time t;
345 zend_ulong length; /* First byte encodes the length*/
346 const zend_uchar *p = *row;
347 DBG_ENTER("ps_fetch_datetime");
348
349 if ((length = php_mysqlnd_net_field_length(row))) {
350 if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) {
351 return;
352 }
353
354 const zend_uchar * to = *row;
355
357 t.neg = 0;
358
359 t.year = (unsigned int) sint2korr(to);
360 t.month = (unsigned int) to[2];
361 t.day = (unsigned int) to[3];
362
363 if (length > 4) {
364 t.hour = (unsigned int) to[4];
365 t.minute = (unsigned int) to[5];
366 t.second = (unsigned int) to[6];
367 } else {
368 t.hour = t.minute = t.second= 0;
369 }
370 t.second_part = (length > 7) ? (zend_ulong) sint4korr(to+7) : 0;
371
372 (*row)+= length;
373 } else {
374 memset(&t, 0, sizeof(t));
376 }
377
378 if (field->decimals > 0 && field->decimals < 7) {
379 ZVAL_STR(zv, zend_strpprintf(0, "%04u-%02u-%02u %02u:%02u:%02u.%0*u",
380 t.year, t.month, t.day, t.hour, t.minute, t.second, field->decimals,
381 (uint32_t) (t.second_part / pow(10, 6 - field->decimals))));
382 } else {
383 ZVAL_STR(zv, zend_strpprintf(0, "%04u-%02u-%02u %02u:%02u:%02u",
384 t.year, t.month, t.day, t.hour, t.minute, t.second));
385 }
387}
388/* }}} */
389
390
391/* {{{ ps_fetch_string */
392static void
393ps_fetch_string(zval * zv, const MYSQLND_FIELD * const field, const unsigned int pack_len, const zend_uchar ** row)
394{
395 const zend_uchar *p = *row;
396 const zend_ulong length = php_mysqlnd_net_field_length(row);
397 if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) {
398 return;
399 }
400 DBG_ENTER("ps_fetch_string");
401 DBG_INF_FMT("len = " ZEND_ULONG_FMT, length);
402 DBG_INF("copying from the row buffer");
403 ZVAL_STRINGL_FAST(zv, (char *)*row, length);
404
405 (*row) += length;
407}
408/* }}} */
409
410
411/* {{{ ps_fetch_bit */
412static void
413ps_fetch_bit(zval * zv, const MYSQLND_FIELD * const field, const unsigned int pack_len, const zend_uchar ** row)
414{
415 const zend_uchar *p = *row;
416 const zend_ulong length = php_mysqlnd_net_field_length(row);
417 if (UNEXPECTED(ps_fetch_is_packet_over_read_with_variable_length(pack_len, row, p, length))) {
418 return;
419 }
420 ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, length);
421}
422/* }}} */
423
424
425/* {{{ _mysqlnd_init_ps_fetch_subsystem */
427{
429 mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].func = ps_fetch_null;
432
433 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].func = ps_fetch_int8;
436
437 mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].func = ps_fetch_int16;
440
441 mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].func = ps_fetch_int16;
444
445 mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].func = ps_fetch_int32;
448
449 mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].func = ps_fetch_int32;
452
453 mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].func = ps_fetch_int64;
456
457 mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].func = ps_fetch_float;
460
461 mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].func = ps_fetch_double;
464
465 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].func = ps_fetch_time;
468
469 mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].func = ps_fetch_date;
472
473 mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].func = ps_fetch_string;
476
477 mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].func = ps_fetch_datetime;
480
481 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].func = ps_fetch_datetime;
484
485 mysqlnd_ps_fetch_functions[MYSQL_TYPE_VECTOR].func = ps_fetch_string;
488
489 mysqlnd_ps_fetch_functions[MYSQL_TYPE_JSON].func = ps_fetch_string;
492
493 mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].func = ps_fetch_string;
496
497 mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].func = ps_fetch_string;
500
504
505 mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].func = ps_fetch_string;
508
509 mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].func = ps_fetch_bit;
512
516
517 mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].func = ps_fetch_string;
520
521 mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].func = ps_fetch_string;
524
525 mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].func = ps_fetch_string;
528
532
533 mysqlnd_ps_fetch_functions[MYSQL_TYPE_ENUM].func = ps_fetch_string;
536
537 mysqlnd_ps_fetch_functions[MYSQL_TYPE_SET].func = ps_fetch_string;
540
541 mysqlnd_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].func = ps_fetch_string;
544}
545/* }}} */
546
547
548/* {{{ mysqlnd_stmt_copy_it */
549static enum_func_status
550mysqlnd_stmt_copy_it(zval ** copies, zval * original, unsigned int param_count, unsigned int current)
551{
552 if (!*copies) {
553 *copies = mnd_ecalloc(param_count, sizeof(zval));
554 }
555 if (*copies) {
556 ZVAL_COPY(&(*copies)[current], original);
557 return PASS;
558 }
559 return FAIL;
560}
561/* }}} */
562
563
564/* {{{ mysqlnd_stmt_free_copies */
565static void
566mysqlnd_stmt_free_copies(MYSQLND_STMT_DATA * stmt, zval *copies)
567{
568 if (copies) {
569 unsigned int i;
570 for (i = 0; i < stmt->param_count; i++) {
571 zval_ptr_dtor(&copies[i]);
572 }
573 mnd_efree(copies);
574 }
575}
576/* }}} */
577
578
579/* {{{ mysqlnd_stmt_execute_check_n_enlarge_buffer */
580static enum_func_status
581mysqlnd_stmt_execute_check_n_enlarge_buffer(zend_uchar **buf, zend_uchar **p, size_t * buf_len, zend_uchar * const provided_buffer, size_t needed_bytes)
582{
583 const size_t overalloc = 5;
584 size_t left = (*buf_len - (*p - *buf));
585
586 if (left < (needed_bytes + overalloc)) {
587 const size_t offset = *p - *buf;
588 zend_uchar *tmp_buf;
589 *buf_len = offset + needed_bytes + overalloc;
590 tmp_buf = mnd_emalloc(*buf_len);
591 if (!tmp_buf) {
592 return FAIL;
593 }
594 memcpy(tmp_buf, *buf, offset);
595 if (*buf != provided_buffer) {
596 mnd_efree(*buf);
597 }
598 *buf = tmp_buf;
599 /* Update our pos pointer */
600 *p = *buf + offset;
601 }
602 return PASS;
603}
604/* }}} */
605
606
607/* {{{ mysqlnd_stmt_execute_prepare_param_types */
608static enum_func_status
609mysqlnd_stmt_execute_prepare_param_types(MYSQLND_STMT_DATA * stmt, zval ** copies_param, int * resend_types_next_time)
610{
611 unsigned int i;
612 DBG_ENTER("mysqlnd_stmt_execute_prepare_param_types");
613 for (i = 0; i < stmt->param_count; i++) {
614 const short current_type = stmt->param_bind[i].type;
615 zval *parameter = &stmt->param_bind[i].zv;
616
617 ZVAL_DEREF(parameter);
618 if (!Z_ISNULL_P(parameter) && (current_type == MYSQL_TYPE_LONG || current_type == MYSQL_TYPE_LONGLONG || current_type == MYSQL_TYPE_TINY)) {
619 /* always copy the var, because we do many conversions */
620 if (Z_TYPE_P(parameter) != IS_LONG &&
621 PASS != mysqlnd_stmt_copy_it(copies_param, parameter, stmt->param_count, i))
622 {
624 goto end;
625 }
626 /*
627 if it doesn't fit in a long send it as a string.
628 Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX
629 */
630 if (Z_TYPE_P(parameter) != IS_LONG) {
631 zval *tmp_data = (*copies_param && !Z_ISUNDEF((*copies_param)[i]))? &(*copies_param)[i]: parameter;
632 /*
633 Because converting to double and back to long can lead
634 to losing precision we need second variable. Conversion to double is to see if
635 value is too big for a long. As said, precision could be lost.
636 */
637 double d = zval_get_double(tmp_data);
638
639 /*
640 if it doesn't fit in a long send it as a string.
641 Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX
642 We do transformation here, which will be used later when sending types. The code later relies on this.
643 */
644 if (d >= (double) ZEND_LONG_MAX || d < (double) ZEND_LONG_MIN) {
645 stmt->send_types_to_server = *resend_types_next_time = 1;
646 convert_to_string(tmp_data);
647 } else {
648 convert_to_long(tmp_data);
649 }
650 }
651 }
652 }
654end:
656}
657/* }}} */
658
659
660/* {{{ mysqlnd_stmt_execute_store_types */
661static void
662mysqlnd_stmt_execute_store_types(MYSQLND_STMT_DATA * stmt, zval * copies, zend_uchar ** p)
663{
664 unsigned int i;
665 for (i = 0; i < stmt->param_count; i++) {
666 short current_type = stmt->param_bind[i].type;
667 zval *parameter = &stmt->param_bind[i].zv;
668 /* our types are not unsigned */
669#if SIZEOF_ZEND_LONG==8
670 if (current_type == MYSQL_TYPE_LONG) {
671 current_type = MYSQL_TYPE_LONGLONG;
672 }
673#endif
674 ZVAL_DEREF(parameter);
675 if (!Z_ISNULL_P(parameter) && (current_type == MYSQL_TYPE_LONG || current_type == MYSQL_TYPE_LONGLONG)) {
676 /*
677 if it doesn't fit in a long send it as a string.
678 Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX
679 */
680 if (Z_TYPE_P(parameter) != IS_LONG) {
681 const zval *tmp_data = (copies && !Z_ISUNDEF(copies[i]))? &copies[i] : parameter;
682 /*
683 In case of IS_LONG we do nothing, it is ok, in case of string, we just need to set current_type.
684 The actual transformation has been performed several dozens line above.
685 */
686 if (Z_TYPE_P(tmp_data) == IS_STRING) {
687 current_type = MYSQL_TYPE_VAR_STRING;
688 /*
689 don't change stmt->param_bind[i].type to MYSQL_TYPE_VAR_STRING
690 we force convert_to_long in all cases, thus the type will be right in the next switch.
691 if the type is however not long, then we will do a goto in the next switch.
692 We want to preserve the original bind type given by the user. Thus, we do these hacks.
693 */
694 }
695 }
696 }
697 int2store(*p, current_type);
698 *p+= 2;
699 }
700}
701/* }}} */
702
703
704/* {{{ mysqlnd_stmt_execute_calculate_param_values_size */
705static enum_func_status
706mysqlnd_stmt_execute_calculate_param_values_size(MYSQLND_STMT_DATA * stmt, zval ** copies_param, size_t * data_size)
707{
708 unsigned int i;
709 DBG_ENTER("mysqlnd_stmt_execute_calculate_param_values_size");
710 for (i = 0; i < stmt->param_count; i++) {
711 unsigned short is_longlong = 0;
712 unsigned int j;
713 zval *bind_var, *the_var = &stmt->param_bind[i].zv;
714
715 bind_var = the_var;
716 ZVAL_DEREF(the_var);
717 if ((stmt->param_bind[i].type != MYSQL_TYPE_LONG_BLOB && Z_TYPE_P(the_var) == IS_NULL)) {
718 continue;
719 }
720
721 if (Z_ISREF_P(bind_var)) {
722 for (j = i + 1; j < stmt->param_count; j++) {
723 if (Z_ISREF(stmt->param_bind[j].zv) && Z_REFVAL(stmt->param_bind[j].zv) == the_var) {
724 /* Double binding of the same zval, make a copy */
725 if (!*copies_param || Z_ISUNDEF((*copies_param)[i])) {
726 if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i)) {
728 goto end;
729 }
730 }
731 break;
732 }
733 }
734 }
735
736 switch (stmt->param_bind[i].type) {
738 *data_size += 8;
739 if (Z_TYPE_P(the_var) != IS_DOUBLE) {
740 if (!*copies_param || Z_ISUNDEF((*copies_param)[i])) {
741 if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i)) {
743 goto end;
744 }
745 }
746 }
747 break;
749 is_longlong = 4;
751 case MYSQL_TYPE_LONG:
752 {
753 zval *tmp_data = (*copies_param && !Z_ISUNDEF((*copies_param)[i]))? &(*copies_param)[i]: the_var;
754 if (Z_TYPE_P(tmp_data) == IS_STRING) {
755 goto use_string;
756 }
757 convert_to_long(tmp_data);
758 }
759 *data_size += 4 + is_longlong;
760 break;
763 /*
764 User hasn't sent anything, we will send empty string.
765 Empty string has length of 0, encoded in 1 byte. No real
766 data will follow after it.
767 */
768 (*data_size)++;
769 }
770 break;
772use_string:
773 *data_size += 8; /* max 8 bytes for size */
774 if (Z_TYPE_P(the_var) != IS_STRING) {
775 if (!*copies_param || Z_ISUNDEF((*copies_param)[i])) {
776 if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i)) {
778 goto end;
779 }
780 }
781 the_var = &((*copies_param)[i]);
782 }
783
784 if (!try_convert_to_string(the_var)) {
785 goto end;
786 }
787 *data_size += Z_STRLEN_P(the_var);
788 break;
789 }
790 }
792end:
794}
795/* }}} */
796
797
798/* {{{ mysqlnd_stmt_execute_store_param_values */
799static void
800mysqlnd_stmt_execute_store_param_values(MYSQLND_STMT_DATA * stmt, zval * copies, zend_uchar * buf, zend_uchar ** p, size_t null_byte_offset)
801{
802 unsigned int i;
803 for (i = 0; i < stmt->param_count; i++) {
804 zval *data, *parameter = &stmt->param_bind[i].zv;
805
806 ZVAL_DEREF(parameter);
807 data = (copies && !Z_ISUNDEF(copies[i]))? &copies[i]: parameter;
808 /* Handle long data */
809 if (!Z_ISUNDEF_P(parameter) && Z_TYPE_P(data) == IS_NULL) {
810 (buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7));
811 } else {
812 switch (stmt->param_bind[i].type) {
816 (*p) += 8;
817 break;
819 if (Z_TYPE_P(data) == IS_STRING) {
820 goto send_string;
821 }
822 /* data has alreade been converted to long */
824 (*p) += 8;
825 break;
826 case MYSQL_TYPE_LONG:
827 if (Z_TYPE_P(data) == IS_STRING) {
828 goto send_string;
829 }
830 /* data has alreade been converted to long */
832 (*p) += 4;
833 break;
834 case MYSQL_TYPE_TINY:
835 if (Z_TYPE_P(data) == IS_STRING) {
836 goto send_string;
837 }
839 (*p)++;
840 break;
844 } else {
845 /* send_long_data() not called, send empty string */
847 }
848 break;
850send_string:
851 {
852 const size_t len = Z_STRLEN_P(data);
853 /* to is after p. The latter hasn't been moved */
856 (*p) += len;
857 }
858 break;
859 default:
860 /* Won't happen, but set to NULL */
861 (buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7));
862 break;
863 }
864 }
865 }
866}
867/* }}} */
868
869
870/* {{{ mysqlnd_stmt_execute_store_params */
871static enum_func_status
872mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar **p, size_t *buf_len )
873{
874 MYSQLND_STMT_DATA * stmt = s->data;
875 zend_uchar * provided_buffer = *buf;
876 size_t data_size = 0;
877 zval *copies = NULL;/* if there are different types */
879 int resend_types_next_time = 0;
880 size_t null_byte_offset;
881
882 DBG_ENTER("mysqlnd_stmt_execute_store_params");
883
884 {
885 unsigned int null_count = (stmt->param_count + 7) / 8;
886 if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, null_count)) {
888 goto end;
889 }
890 /* put `null` bytes */
891 null_byte_offset = *p - *buf;
892 memset(*p, 0, null_count);
893 *p += null_count;
894 }
895
896/* 1. Store type information */
897 /*
898 check if need to send the types even if stmt->send_types_to_server is 0. This is because
899 if we send "i" (42) then the type will be int and the server will expect int. However, if next
900 time we try to send > LONG_MAX, the conversion to string will send a string and the server
901 won't expect it and interpret the value as 0. Thus we need to resend the types, if any such values
902 occur, and force resend for the next execution.
903 */
904 if (FAIL == mysqlnd_stmt_execute_prepare_param_types(stmt, &copies, &resend_types_next_time)) {
905 goto end;
906 }
907
909 (*p)++;
910
911 if (stmt->send_types_to_server) {
912 if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, stmt->param_count * 2)) {
914 goto end;
915 }
916 mysqlnd_stmt_execute_store_types(stmt, copies, p);
917 }
918
919 stmt->send_types_to_server = resend_types_next_time;
920
921/* 2. Store data */
922 /* 2.1 Calculate how much space we need */
923 if (FAIL == mysqlnd_stmt_execute_calculate_param_values_size(stmt, &copies, &data_size)) {
924 goto end;
925 }
926
927 /* 2.2 Enlarge the buffer, if needed */
928 if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, data_size)) {
930 goto end;
931 }
932
933 /* 2.3 Store the actual data */
934 mysqlnd_stmt_execute_store_param_values(stmt, copies, *buf, p, null_byte_offset);
935
936 ret = PASS;
937end:
938 mysqlnd_stmt_free_copies(stmt, copies);
939
940 DBG_INF_FMT("ret=%s", ret == PASS? "PASS":"FAIL");
942}
943/* }}} */
944
945
946/* {{{ mysqlnd_stmt_execute_generate_request */
948mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * const s, zend_uchar ** request, size_t *request_len, bool * free_buffer)
949{
950 MYSQLND_STMT_DATA * stmt = s->data;
952 *cmd_buffer = stmt->execute_cmd_buffer.buffer;
953 size_t cmd_buffer_length = stmt->execute_cmd_buffer.length;
955
956 DBG_ENTER("mysqlnd_stmt_execute_generate_request");
957
958 int4store(p, stmt->stmt_id);
959 p += 4;
960
961 /* flags is 4 bytes, we store just 1 */
962 int1store(p, (zend_uchar) stmt->flags);
963 p++;
964
965 /* Make it all zero */
966 int4store(p, 0);
967
968 int1store(p, 1); /* and send 1 for iteration count */
969 p+= 4;
970
971 if (stmt->param_count != 0) {
972 ret = mysqlnd_stmt_execute_store_params(s, &cmd_buffer, &p, &cmd_buffer_length);
973 }
974
975 *free_buffer = (cmd_buffer != stmt->execute_cmd_buffer.buffer);
976 *request_len = (p - cmd_buffer);
977 *request = cmd_buffer;
978 DBG_INF_FMT("ret=%s", ret == PASS? "PASS":"FAIL");
980}
981/* }}} */
size_t len
Definition apprentice.c:174
pow(mixed $num, mixed $exponent)
char s[4]
Definition cdf.c:77
#define uint4korr(A)
Definition config-win.h:51
#define int4store(T, A)
Definition config-win.h:63
#define sint3korr(A)
Definition config-win.h:40
#define float8store(T, V)
Definition config-win.h:73
#define sint4korr(A)
Definition config-win.h:48
#define int2store(T, A)
Definition config-win.h:59
#define float8get(V, M)
Definition config-win.h:71
#define int8store(T, A)
Definition config-win.h:69
#define float4get(V, M)
Definition config-win.h:75
#define sint8korr(A)
Definition config-win.h:58
#define sint2korr(A)
Definition config-win.h:39
#define uint2korr(A)
Definition config-win.h:49
#define uint3korr(A)
Definition config-win.h:50
#define uint8korr(A)
Definition config-win.h:57
zval * zv
Definition ffi.c:3975
memcpy(ptr1, ptr2, size)
memset(ptr, 0, type->size)
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
zend_long offset
#define NULL
Definition gdcache.h:45
#define PASS(tables)
Definition hash_gost.c:193
again j
PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format,...)
Definition main.c:1173
lu_byte left
Definition minilua.c:4266
#define mnd_efree(ptr)
#define mnd_ecalloc(nmemb, size)
#define mnd_emalloc(size)
#define DBG_VOID_RETURN
#define DBG_RETURN(value)
#define MYSQL_TYPE_LAST
#define ZEROFILL_FLAG
#define UNSIGNED_FLAG
@ MYSQL_TYPE_VARCHAR
@ MYSQL_TYPE_LONGLONG
@ MYSQL_TYPE_LONG_BLOB
@ MYSQL_TYPE_VAR_STRING
@ MYSQL_TYPE_BLOB
@ MYSQL_TYPE_TINY
@ MYSQL_TYPE_TIME
@ MYSQL_TYPE_SET
@ MYSQL_TYPE_NEWDATE
@ MYSQL_TYPE_VECTOR
@ MYSQL_TYPE_JSON
@ MYSQL_TYPE_STRING
@ MYSQL_TYPE_NULL
@ MYSQL_TYPE_ENUM
@ MYSQL_TYPE_TINY_BLOB
@ MYSQL_TYPE_LONG
@ MYSQL_TYPE_BIT
@ MYSQL_TYPE_GEOMETRY
@ MYSQL_TYPE_NEWDECIMAL
@ MYSQL_TYPE_DECIMAL
@ MYSQL_TYPE_DOUBLE
@ MYSQL_TYPE_MEDIUM_BLOB
@ MYSQL_TYPE_SHORT
@ MYSQL_TYPE_DATE
@ MYSQL_TYPE_FLOAT
@ MYSQL_TYPE_TIMESTAMP
@ MYSQL_TYPE_INT24
@ MYSQL_TYPE_DATETIME
@ MYSQL_TYPE_YEAR
@ MYSQLND_PARAM_BIND_BLOB_USED
enum func_status enum_func_status
#define bit_uint7korr(A)
#define int1store(T, A)
#define bit_uint3korr(A)
#define bit_uint6korr(A)
#define bit_uint5korr(A)
#define bit_uint2korr(A)
#define bit_uint4korr(A)
#define uint1korr(A)
#define bit_uint8korr(A)
mysqlnd_stmt_execute_generate_request
struct st_mysqlnd_perm_bind mysqlnd_ps_fetch_functions[MYSQL_TYPE_LAST+1]
void ps_fetch_from_1_to_8_bytes(zval *zv, const MYSQLND_FIELD *const field, const unsigned int pack_len, const zend_uchar **row, unsigned int byte_count)
#define MYSQLND_PS_SKIP_RESULT_W_LEN
mysqlnd_timestamp_type
@ MYSQLND_TIMESTAMP_TIME
@ MYSQLND_TIMESTAMP_ERROR
@ MYSQLND_TIMESTAMP_DATE
@ MYSQLND_TIMESTAMP_NONE
@ MYSQLND_TIMESTAMP_DATETIME
#define NOT_FIXED_DEC
void _mysqlnd_init_ps_fetch_subsystem(void)
#define MYSQLND_PS_SKIP_RESULT_STR
struct st_mysqlnd_field MYSQLND_FIELD
struct st_mysqlnd_stmt_data MYSQLND_STMT_DATA
struct st_mysqlnd_stmt MYSQLND_STMT
#define SET_OOM_ERROR(info)
zend_ulong php_mysqlnd_net_field_length(const zend_uchar **packet)
zend_uchar * php_mysqlnd_net_store_length(zend_uchar *packet, const uint64_t length)
#define INT_MAX
Definition php.h:237
unsigned const char * end
Definition php_ffi.h:51
#define L64
Definition php_hash.h:30
zend_constant * data
zval * current
Definition session.c:1024
p
Definition session.c:1105
#define FAIL(...)
enum_param_bind_flags flags
MYSQLND_CMD_BUFFER execute_cmd_buffer
unsigned char send_types_to_server
MYSQLND_ERROR_INFO * error_info
MYSQLND_PARAM_BIND * param_bind
zend_ulong second_part
unsigned int second
unsigned int year
enum mysqlnd_timestamp_type time_type
unsigned int minute
unsigned int hour
unsigned int month
ZEND_API zend_string * zend_strpprintf(size_t max_len, const char *format,...)
Definition zend.c:353
#define ZVAL_STRINGL_FAST(z, s, l)
Definition zend_API.h:983
struct _zval_struct zval
#define E_WARNING
Definition zend_errors.h:24
#define ZEND_ULONG_FMT
Definition zend_long.h:88
int32_t zend_long
Definition zend_long.h:42
#define ZEND_LONG_MIN
Definition zend_long.h:46
uint32_t zend_ulong
Definition zend_long.h:43
#define ZEND_LONG_MAX
Definition zend_long.h:45
ZEND_API zend_string *ZEND_FASTCALL zend_u64_to_str(uint64_t num)
ZEND_API zend_string *ZEND_FASTCALL zend_i64_to_str(int64_t num)
ZEND_API void ZEND_FASTCALL convert_to_double(zval *op)
ZEND_API void ZEND_FASTCALL convert_to_long(zval *op)
#define convert_to_string(op)
#define ZEND_FALLTHROUGH
#define UNEXPECTED(condition)
#define dval(x)
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define ZVAL_STR(z, s)
#define Z_ISREF_P(zval_p)
Definition zend_types.h:954
#define Z_STRVAL_P(zval_p)
Definition zend_types.h:975
#define Z_ISUNDEF_P(zval_p)
Definition zend_types.h:957
#define ZVAL_NULL(z)
#define ZVAL_DEREF(z)
#define ZVAL_LONG(z, l)
#define IS_STRING
Definition zend_types.h:606
#define Z_ISNULL_P(zval_p)
Definition zend_types.h:960
#define IS_DOUBLE
Definition zend_types.h:605
#define Z_ISUNDEF(zval)
Definition zend_types.h:956
#define Z_REFVAL(zval)
#define Z_STRLEN_P(zval_p)
Definition zend_types.h:978
#define IS_NULL
Definition zend_types.h:601
#define IS_LONG
Definition zend_types.h:604
#define ZVAL_COPY(z, v)
#define ZVAL_DOUBLE(z, d)
unsigned char zend_uchar
Definition zend_types.h:57
#define Z_ISREF(zval)
Definition zend_types.h:953
#define Z_DVAL_P(zval_p)
Definition zend_types.h:969
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
zval * ret
value