1/****************************************************************************
2 Copyright (C) 2012 Monty Program AB
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with this library; if not see <http://www.gnu.org/licenses>
16 or write to the Free Software Foundation, Inc.,
17 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
18
19 Part of this code includes code from the PHP project which
20 is freely available from http://www.php.net
21*****************************************************************************/
22
23/* The implementation for prepared statements was ported from PHP's mysqlnd
24 extension, written by Andrey Hristov, Georg Richter and Ulf Wendel
25
26 Original file header:
27 +----------------------------------------------------------------------+
28 | PHP Version 5 |
29 +----------------------------------------------------------------------+
30 | Copyright (c) 2006-2011 The PHP Group |
31 +----------------------------------------------------------------------+
32 | This source file is subject to version 3.01 of the PHP license, |
33 | that is bundled with this package in the file LICENSE, and is |
34 | available through the world-wide-web at the following url: |
35 | http://www.php.net/license/3_01.txt |
36 | If you did not receive a copy of the PHP license and are unable to |
37 | obtain it through the world-wide-web, please send a note to |
38 | license@php.net so we can mail you a copy immediately. |
39 +----------------------------------------------------------------------+
40 | Authors: Georg Richter <georg@mysql.com> |
41 | Andrey Hristov <andrey@mysql.com> |
42 | Ulf Wendel <uwendel@mysql.com> |
43 +----------------------------------------------------------------------+
44*/
45
46#include "ma_global.h"
47#include <ma_sys.h>
48#include <ma_string.h>
49#include <mariadb_ctype.h>
50#include "mysql.h"
51#include <math.h> /* ceil() */
52
53#ifdef WIN32
54#include <malloc.h>
55#endif
56
57#define MYSQL_SILENT
58
59/* ranges for C-binding */
60#define UINT_MAX32 0xFFFFFFFFL
61#define UINT_MAX24 0x00FFFFFF
62#define UINT_MAX16 0xFFFF
63#ifndef INT_MIN8
64#define INT_MIN8 (~0x7F)
65#define INT_MAX8 0x7F
66#endif
67#define UINT_MAX8 0xFF
68
69 #define MAX_DOUBLE_STRING_REP_LENGTH 300
70#if defined(HAVE_LONG_LONG) && !defined(LONGLONG_MIN)
71#define LONGLONG_MIN ((long long) 0x8000000000000000LL)
72#define LONGLONG_MAX ((long long) 0x7FFFFFFFFFFFFFFFLL)
73#endif
74
75#if defined(HAVE_LONG_LONG) && !defined(ULONGLONG_MAX)
76/* First check for ANSI C99 definition: */
77#ifdef ULLONG_MAX
78#define ULONGLONG_MAX ULLONG_MAX
79#else
80#define ULONGLONG_MAX ((unsigned long long)(~0ULL))
81#endif
82#endif /* defined (HAVE_LONG_LONG) && !defined(ULONGLONG_MAX)*/
83
84#define YY_PART_YEAR 70
85
86MYSQL_PS_CONVERSION mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY + 1];
87my_bool mysql_ps_subsystem_initialized= 0;
88
89
90#define NUMERIC_TRUNCATION(val,min_range, max_range)\
91 ((((val) > (max_range)) || ((val) < (min_range)) ? 1 : 0))
92
93
94void ma_bmove_upp(register char *dst, register const char *src, register size_t len)
95{
96 while (len-- != 0) *--dst = *--src;
97}
98
99/* {{{ ps_fetch_from_1_to_8_bytes */
100void ps_fetch_from_1_to_8_bytes(MYSQL_BIND *r_param, const MYSQL_FIELD * const field,
101 unsigned char **row, unsigned int byte_count)
102{
103 my_bool is_unsigned= test(field->flags & UNSIGNED_FLAG);
104 r_param->buffer_length= byte_count;
105 switch (byte_count) {
106 case 1:
107 *(uchar *)r_param->buffer= **row;
108 *r_param->error= is_unsigned != r_param->is_unsigned && *(uchar *)r_param->buffer > INT_MAX8;
109 break;
110 case 2:
111 shortstore(r_param->buffer, ((ushort) sint2korr(*row)));
112 *r_param->error= is_unsigned != r_param->is_unsigned && *(ushort *)r_param->buffer > INT_MAX16;
113 break;
114 case 4:
115 {
116 longstore(r_param->buffer, ((uint32)sint4korr(*row)));
117 *r_param->error= is_unsigned != r_param->is_unsigned && *(uint32 *)r_param->buffer > INT_MAX32;
118 }
119 break;
120 case 8:
121 {
122 ulonglong val= (ulonglong)sint8korr(*row);
123 longlongstore(r_param->buffer, val);
124 *r_param->error= is_unsigned != r_param->is_unsigned && val > LONGLONG_MAX ;
125 }
126 break;
127 default:
128 r_param->buffer_length= 0;
129 break;
130 }
131 (*row)+= byte_count;
132}
133/* }}} */
134
135static unsigned long long my_strtoull(const char *str, size_t len, const char **end, int *err)
136{
137 unsigned long long val = 0;
138 const char *p = str;
139 const char *end_str = p + len;
140
141 for (; p < end_str; p++)
142 {
143 if (*p < '0' || *p > '9')
144 break;
145
146 if (val > ULONGLONG_MAX /10 || val*10 > ULONGLONG_MAX - (*p - '0'))
147 {
148 *err = ERANGE;
149 break;
150 }
151 val = val * 10 + *p -'0';
152 }
153
154 if (p == str)
155 /* Did not parse anything.*/
156 *err = ERANGE;
157
158 *end = p;
159 return val;
160}
161
162static long long my_strtoll(const char *str, size_t len, const char **end, int *err)
163{
164 unsigned long long uval = 0;
165 const char *p = str;
166 const char *end_str = p + len;
167 int neg;
168
169 while (p < end_str && isspace(*p))
170 p++;
171
172 if (p == end_str)
173 {
174 *end = p;
175 *err = ERANGE;
176 return 0;
177 }
178
179 neg = *p == '-';
180 if (neg)
181 p++;
182
183 uval = my_strtoull(p, (end_str - p), &p, err);
184 *end = p;
185 if (*err)
186 return uval;
187
188 if (!neg)
189 {
190 /* Overflow of the long long range. */
191 if (uval > LONGLONG_MAX)
192 {
193 *end = p - 1;
194 uval = LONGLONG_MAX;
195 *err = ERANGE;
196 }
197 return uval;
198 }
199
200 if (uval == (unsigned long long) LONGLONG_MIN)
201 return LONGLONG_MIN;
202
203 if (uval > LONGLONG_MAX)
204 {
205 *end = p - 1;
206 uval = LONGLONG_MIN;
207 *err = ERANGE;
208 }
209
210 return -1LL * uval;
211}
212
213
214static long long my_atoll(const char *str, const char *end_str, int *error)
215{
216 const char *p=str;
217 const char *end;
218 long long ret;
219 while (p < end_str && isspace(*p))
220 p++;
221
222 ret = my_strtoll(p, end_str - p, &end, error);
223
224 while(end < end_str && isspace(*end))
225 end++;
226
227 if(end != end_str)
228 *error= 1;
229
230 return ret;
231}
232
233
234static unsigned long long my_atoull(const char *str, const char *end_str, int *error)
235{
236 const char *p = str;
237 const char *end;
238 unsigned long long ret;
239
240 while (p < end_str && isspace(*p))
241 p++;
242
243 ret = my_strtoull(p, end_str - p, &end, error);
244
245 while(end < end_str && isspace(*end))
246 end++;
247
248 if(end != end_str)
249 *error= 1;
250
251 return ret;
252}
253
254double my_atod(const char *number, const char *end, int *error)
255{
256 double val= 0.0;
257 char buffer[255];
258 int len= (int)(end - number);
259
260 if (len > 254)
261 *error= 1;
262
263 len= MIN(len, 254);
264 memcpy(&buffer, number, len);
265 buffer[len]= '\0';
266
267 val= strtod(buffer, NULL);
268/* if (!*error)
269 *error= errno; */
270 return val;
271}
272
273
274/*
275 strtoui() version, that works for non-null terminated strings
276*/
277static unsigned int my_strtoui(const char *str, size_t len, const char **end, int *err)
278{
279 unsigned long long ull = my_strtoull(str, len, end, err);
280 if (ull > UINT_MAX)
281 *err = ERANGE;
282 return (unsigned int)ull;
283}
284
285/*
286 Parse time, in MySQL format.
287
288 the input string needs is in form "hour:minute:second[.fraction]"
289 hour, minute and second can have leading zeroes or not,
290 they are not necessarily 2 chars.
291
292 Hour must be < 838, minute < 60, second < 60
293 Only 6 places of fraction are considered, the value is truncated after 6 places.
294*/
295static const unsigned int frac_mul[] = { 1000000,100000,10000,1000,100,10 };
296
297static int parse_time(const char *str, size_t length, const char **end_ptr, MYSQL_TIME *tm)
298{
299 int err= 0;
300 const char *p = str;
301 const char *end = str + length;
302 size_t frac_len;
303 int ret=1;
304
305 tm->hour = my_strtoui(p, end-p, &p, &err);
306 if (err || tm->hour > 838 || p == end || *p != ':' )
307 goto end;
308
309 p++;
310 tm->minute = my_strtoui(p, end-p, &p, &err);
311 if (err || tm->minute > 59 || p == end || *p != ':')
312 goto end;
313
314 p++;
315 tm->second = my_strtoui(p, end-p, &p, &err);
316 if (err || tm->second > 59)
317 goto end;
318
319 ret = 0;
320 tm->second_part = 0;
321
322 if (p == end)
323 goto end;
324
325 /* Check for fractional part*/
326 if (*p != '.')
327 goto end;
328
329 p++;
330 frac_len = MIN(6,end-p);
331
332 tm->second_part = my_strtoui(p, frac_len, &p, &err);
333 if (err)
334 goto end;
335
336 if (frac_len < 6)
337 tm->second_part *= frac_mul[frac_len];
338
339 ret = 0;
340
341 /* Consume whole fractional part, even after 6 digits.*/
342 p += frac_len;
343 while(p < *end_ptr)
344 {
345 if (*p < '0' || *p > '9')
346 break;
347 p++;
348 }
349end:
350 *end_ptr = p;
351 return ret;
352}
353
354
355/*
356 Parse date, in MySQL format.
357
358 The input string needs is in form "year-month-day"
359 year, month and day can have leading zeroes or not,
360 they do not have fixed length.
361
362 Year must be < 10000, month < 12, day < 32
363
364 Years with 2 digits, are coverted to values 1970-2069 according to
365 usual rules:
366
367 00-69 is converted to 2000-2069.
368 70-99 is converted to 1970-1999.
369*/
370static int parse_date(const char *str, size_t length, const char **end_ptr, MYSQL_TIME *tm)
371{
372 int err = 0;
373 const char *p = str;
374 const char *end = str + length;
375 int ret = 1;
376
377 tm->year = my_strtoui(p, end - p, &p, &err);
378 if (err || tm->year > 9999 || p == end || *p != '-')
379 goto end;
380
381 if (p - str == 2) // 2-digit year
382 tm->year += (tm->year >= 70) ? 1900 : 2000;
383
384 p++;
385 tm->month = my_strtoui(p,end -p, &p, &err);
386 if (err || tm->month > 12 || p == end || *p != '-')
387 goto end;
388
389 p++;
390 tm->day = my_strtoui(p, end -p , &p, &err);
391 if (err || tm->day > 31)
392 goto end;
393
394 ret = 0;
395
396end:
397 *end_ptr = p;
398 return ret;
399}
400
401/*
402 Parse (not null terminated) string representing
403 TIME, DATE, or DATETIME into MYSQL_TIME structure
404
405 The supported formats by this functions are
406 - TIME : [-]hours:minutes:seconds[.fraction]
407 - DATE : year-month-day
408 - DATETIME : year-month-day<space>hours:minutes:seconds[.fraction]
409
410 cf https://dev.mysql.com/doc/refman/8.0/en/datetime.html
411
412 Whitespaces are trimmed from the start and end of the string.
413 The function ignores junk at the end of the string.
414
415 Parts of date of time do not have fixed length, so that parsing is compatible with server.
416 However server supports additional formats, e.g YYYYMMDD, HHMMSS, which this function does
417 not support.
418
419*/
420int str_to_TIME(const char *str, size_t length, MYSQL_TIME *tm)
421{
422 const char *p = str;
423 const char *end = str + length;
424 int is_time = 0;
425
426 if (!p)
427 goto error;
428
429 while (p < end && isspace(*p))
430 p++;
431 while (p < end && isspace(end[-1]))
432 end--;
433
434 if (end -p < 5)
435 goto error;
436
437 if (*p == '-')
438 {
439 tm->neg = 1;
440 /* Only TIME can't be negative.*/
441 is_time = 1;
442 p++;
443 }
444 else
445 {
446 int i;
447 tm->neg = 0;
448 /*
449 Date parsing (in server) accepts leading zeroes, thus position of the delimiters
450 is not fixed. Scan the string to find out what we need to parse.
451 */
452 for (i = 1; p + i < end; i++)
453 {
454 if(p[i] == '-' || p [i] == ':')
455 {
456 is_time = p[i] == ':';
457 break;
458 }
459 }
460 }
461
462 if (is_time)
463 {
464 if (parse_time(p, end - p, &p, tm))
465 goto error;
466
467 tm->year = tm->month = tm->day = 0;
468 tm->time_type = MYSQL_TIMESTAMP_TIME;
469 return 0;
470 }
471
472 if (parse_date(p, end - p, &p, tm))
473 goto error;
474
475 if (p == end || p[0] != ' ')
476 {
477 tm->hour = tm->minute = tm->second = tm->second_part = 0;
478 tm->time_type = MYSQL_TIMESTAMP_DATE;
479 return 0;
480 }
481
482 /* Skip space. */
483 p++;
484 if (parse_time(p, end - p, &p, tm))
485 goto error;
486
487 /* In DATETIME, hours must be < 24.*/
488 if (tm->hour > 23)
489 goto error;
490
491 tm->time_type = MYSQL_TIMESTAMP_DATETIME;
492 return 0;
493
494error:
495 memset(tm, 0, sizeof(*tm));
496 tm->time_type = MYSQL_TIMESTAMP_ERROR;
497 return 1;
498}
499
500
501static void convert_froma_string(MYSQL_BIND *r_param, char *buffer, size_t len)
502{
503 int error= 0;
504 switch (r_param->buffer_type)
505 {
506 case MYSQL_TYPE_TINY:
507 {
508 longlong val= my_atoll(buffer, buffer + len, &error);
509 *r_param->error= error ? 1 : r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX8) : NUMERIC_TRUNCATION(val, INT_MIN8, INT_MAX8) || error > 0;
510 int1store(r_param->buffer, (uchar) val);
511 r_param->buffer_length= sizeof(uchar);
512 }
513 break;
514 case MYSQL_TYPE_YEAR:
515 case MYSQL_TYPE_SHORT:
516 {
517 longlong val= my_atoll(buffer, buffer + len, &error);
518 *r_param->error= error ? 1 : r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX16) : NUMERIC_TRUNCATION(val, INT_MIN16, INT_MAX16) || error > 0;
519 shortstore(r_param->buffer, (short)val);
520 r_param->buffer_length= sizeof(short);
521 }
522 break;
523 case MYSQL_TYPE_LONG:
524 {
525 longlong val= my_atoll(buffer, buffer + len, &error);
526 *r_param->error=error ? 1 : r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX32) : NUMERIC_TRUNCATION(val, INT_MIN32, INT_MAX32) || error > 0;
527 longstore(r_param->buffer, (int32)val);
528 r_param->buffer_length= sizeof(uint32);
529 }
530 break;
531 case MYSQL_TYPE_LONGLONG:
532 {
533 longlong val= r_param->is_unsigned ? (longlong)my_atoull(buffer, buffer + len, &error) : my_atoll(buffer, buffer + len, &error);
534 *r_param->error= error > 0; /* no need to check for truncation */
535 longlongstore(r_param->buffer, val);
536 r_param->buffer_length= sizeof(longlong);
537 }
538 break;
539 case MYSQL_TYPE_DOUBLE:
540 {
541 double val= my_atod(buffer, buffer + len, &error);
542 *r_param->error= error > 0; /* no need to check for truncation */
543 doublestore((uchar *)r_param->buffer, val);
544 r_param->buffer_length= sizeof(double);
545 }
546 break;
547 case MYSQL_TYPE_FLOAT:
548 {
549 float val= (float)my_atod(buffer, buffer + len, &error);
550 *r_param->error= error > 0; /* no need to check for truncation */
551 floatstore((uchar *)r_param->buffer, val);
552 r_param->buffer_length= sizeof(float);
553 }
554 break;
555 case MYSQL_TYPE_TIME:
556 case MYSQL_TYPE_DATE:
557 case MYSQL_TYPE_DATETIME:
558 case MYSQL_TYPE_TIMESTAMP:
559 {
560 MYSQL_TIME *tm= (MYSQL_TIME *)r_param->buffer;
561 str_to_TIME(buffer, len, tm);
562 break;
563 }
564 break;
565 case MYSQL_TYPE_TINY_BLOB:
566 case MYSQL_TYPE_MEDIUM_BLOB:
567 case MYSQL_TYPE_LONG_BLOB:
568 case MYSQL_TYPE_BLOB:
569 case MYSQL_TYPE_DECIMAL:
570 case MYSQL_TYPE_NEWDECIMAL:
571 default:
572 {
573 char *start= buffer + r_param->offset; /* stmt_fetch_column sets offset */
574 char *end= buffer + len;
575 size_t copylen= 0;
576
577 if (start < end)
578 {
579 copylen= end - start;
580 if (r_param->buffer_length)
581 memcpy(r_param->buffer, start, MIN(copylen, r_param->buffer_length));
582 }
583 if (copylen < r_param->buffer_length)
584 ((char *)r_param->buffer)[copylen]= 0;
585 *r_param->error= (copylen > r_param->buffer_length);
586
587 *r_param->length= (ulong)len;
588 }
589 break;
590 }
591}
592
593static void convert_from_long(MYSQL_BIND *r_param, const MYSQL_FIELD *field, longlong val, my_bool is_unsigned)
594{
595 switch (r_param->buffer_type) {
596 case MYSQL_TYPE_TINY:
597 *(uchar *)r_param->buffer= (uchar)val;
598 *r_param->error= r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX8) : NUMERIC_TRUNCATION(val, INT_MIN8, INT_MAX8);
599 r_param->buffer_length= 1;
600 break;
601 case MYSQL_TYPE_SHORT:
602 case MYSQL_TYPE_YEAR:
603 shortstore(r_param->buffer, (short)val);
604 *r_param->error= r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX16) : NUMERIC_TRUNCATION(val, INT_MIN16, INT_MAX16);
605 r_param->buffer_length= 2;
606 break;
607 case MYSQL_TYPE_LONG:
608 longstore(r_param->buffer, (int32)val);
609 *r_param->error= r_param->is_unsigned ? NUMERIC_TRUNCATION(val, 0, UINT_MAX32) : NUMERIC_TRUNCATION(val, INT_MIN32, INT_MAX32);
610 r_param->buffer_length= 4;
611 break;
612 case MYSQL_TYPE_LONGLONG:
613 *r_param->error= (val < 0 && r_param->is_unsigned != is_unsigned);
614 longlongstore(r_param->buffer, val);
615 r_param->buffer_length= 8;
616 break;
617 case MYSQL_TYPE_DOUBLE:
618 {
619 volatile double dbl;
620
621 dbl= (is_unsigned) ? ulonglong2double((ulonglong)val) : (double)val;
622 doublestore(r_param->buffer, dbl);
623
624 *r_param->error = (dbl != ceil(dbl)) ||
625 (is_unsigned ? (ulonglong )dbl != (ulonglong)val :
626 (longlong)dbl != (longlong)val);
627
628 r_param->buffer_length= 8;
629 break;
630 }
631 case MYSQL_TYPE_FLOAT:
632 {
633 float fval;
634 fval= is_unsigned ? (float)(ulonglong)(val) : (float)val;
635 floatstore((uchar *)r_param->buffer, fval);
636 *r_param->error= (fval != ceilf(fval)) ||
637 (is_unsigned ? (ulonglong)fval != (ulonglong)val :
638 (longlong)fval != val);
639 r_param->buffer_length= 4;
640 }
641 break;
642 default:
643 {
644 char *buffer;
645 char *endptr;
646 uint len;
647 my_bool zf_truncated= 0;
648
649 buffer= alloca(MAX(field->length, 22));
650 endptr= ma_ll2str(val, buffer, is_unsigned ? 10 : -10);
651 len= (uint)(endptr - buffer);
652
653 /* check if field flag is zerofill */
654 if (field->flags & ZEROFILL_FLAG)
655 {
656 uint display_width= MAX(field->length, len);
657 if (display_width < r_param->buffer_length)
658 {
659 ma_bmove_upp(buffer + display_width, buffer + len, len);
660 /* coverity [bad_memset] */
661 memset((void*) buffer, (int) '0', display_width - len);
662 len= display_width;
663 }
664 else
665 zf_truncated= 1;
666 }
667 convert_froma_string(r_param, buffer, len);
668 *r_param->error+= zf_truncated;
669 }
670 break;
671 }
672}
673
674
675/* {{{ ps_fetch_null */
676static
677void ps_fetch_null(MYSQL_BIND *r_param __attribute__((unused)),
678 const MYSQL_FIELD * field __attribute__((unused)),
679 unsigned char **row __attribute__((unused)))
680{
681 /* do nothing */
682}
683/* }}} */
684
685#define GET_LVALUE_FROM_ROW(is_unsigned, data, ucast, scast)\
686 (is_unsigned) ? (longlong)(ucast) *(longlong *)(data) : (longlong)(scast) *(longlong *)(data)
687/* {{{ ps_fetch_int8 */
688static
689void ps_fetch_int8(MYSQL_BIND *r_param, const MYSQL_FIELD * const field,
690 unsigned char **row)
691{
692 switch(r_param->buffer_type) {
693 case MYSQL_TYPE_TINY:
694 ps_fetch_from_1_to_8_bytes(r_param, field, row, 1);
695 break;
696 default:
697 {
698 uchar val= **row;
699 longlong lval= field->flags & UNSIGNED_FLAG ? (longlong) val : (longlong)(signed char)val;
700 convert_from_long(r_param, field, lval, field->flags & UNSIGNED_FLAG);
701 (*row) += 1;
702 }
703 break;
704 }
705}
706/* }}} */
707
708
709/* {{{ ps_fetch_int16 */
710static
711void ps_fetch_int16(MYSQL_BIND *r_param, const MYSQL_FIELD * const field,
712 unsigned char **row)
713{
714 switch (r_param->buffer_type) {
715 case MYSQL_TYPE_YEAR:
716 case MYSQL_TYPE_SHORT:
717 ps_fetch_from_1_to_8_bytes(r_param, field, row, 2);
718 break;
719 default:
720 {
721 short sval= sint2korr(*row);
722 longlong lval= field->flags & UNSIGNED_FLAG ? (longlong)(ushort) sval : (longlong)sval;
723 convert_from_long(r_param, field, lval, field->flags & UNSIGNED_FLAG);
724 (*row) += 2;
725 }
726 break;
727 }
728}
729/* }}} */
730
731
732/* {{{ ps_fetch_int32 */
733static
734void ps_fetch_int32(MYSQL_BIND *r_param, const MYSQL_FIELD * const field,
735 unsigned char **row)
736{
737 switch (r_param->buffer_type) {
738/* case MYSQL_TYPE_TINY:
739 ps_fetch_from_1_to_8_bytes(r_param, field, row, 1);
740 break;
741 case MYSQL_TYPE_YEAR:
742 case MYSQL_TYPE_SHORT:
743 ps_fetch_from_1_to_8_bytes(r_param, field, row, 2);
744 break; */
745 case MYSQL_TYPE_INT24:
746 case MYSQL_TYPE_LONG:
747 ps_fetch_from_1_to_8_bytes(r_param, field, row, 4);
748 break;
749 default:
750 {
751 int32 sval= sint4korr(*row);
752 longlong lval= field->flags & UNSIGNED_FLAG ? (longlong)(uint32) sval : (longlong)sval;
753 convert_from_long(r_param, field, lval, field->flags & UNSIGNED_FLAG);
754 (*row) += 4;
755 }
756 break;
757 }
758}
759/* }}} */
760
761
762/* {{{ ps_fetch_int64 */
763static
764void ps_fetch_int64(MYSQL_BIND *r_param, const MYSQL_FIELD * const field,
765 unsigned char **row)
766{
767 switch(r_param->buffer_type)
768 {
769/* case MYSQL_TYPE_TINY:
770 ps_fetch_from_1_to_8_bytes(r_param, field, row, 1);
771 break;
772 case MYSQL_TYPE_YEAR:
773 case MYSQL_TYPE_SHORT:
774 ps_fetch_from_1_to_8_bytes(r_param, field, row, 2);
775 break;
776 case MYSQL_TYPE_INT24:
777 case MYSQL_TYPE_LONG:
778 ps_fetch_from_1_to_8_bytes(r_param, field, row, 4);
779 break; */
780 case MYSQL_TYPE_LONGLONG:
781 ps_fetch_from_1_to_8_bytes(r_param, field, row, 8);
782 break;
783 default:
784 {
785 longlong sval= (longlong)sint8korr(*row);
786 longlong lval= field->flags & UNSIGNED_FLAG ? (longlong)(ulonglong) sval : (longlong)sval;
787 convert_from_long(r_param, field, lval, field->flags & UNSIGNED_FLAG);
788 (*row) += 8;
789 }
790 break;
791 }
792}
793/* }}} */
794
795static void convert_from_float(MYSQL_BIND *r_param, const MYSQL_FIELD *field, float val, int size __attribute__((unused)))
796{
797 double check_trunc_val= (val > 0) ? floor(val) : -floor(-val);
798 char *buf= (char *)r_param->buffer;
799 switch (r_param->buffer_type)
800 {
801 case MYSQL_TYPE_TINY:
802 *buf= (r_param->is_unsigned) ? (uint8)val : (int8)val;
803 *r_param->error= check_trunc_val != (r_param->is_unsigned ? (double)((uint8)*buf) :
804 (double)((int8)*buf));
805 r_param->buffer_length= 1;
806 break;
807 case MYSQL_TYPE_SHORT:
808 case MYSQL_TYPE_YEAR:
809 {
810 if (r_param->is_unsigned)
811 {
812 ushort sval= (ushort)val;
813 shortstore(buf, sval);
814 *r_param->error= check_trunc_val != (double)sval;
815 } else {
816 short sval= (short)val;
817 shortstore(buf, sval);
818 *r_param->error= check_trunc_val != (double)sval;
819 }
820 r_param->buffer_length= 2;
821 }
822 break;
823 case MYSQL_TYPE_LONG:
824 {
825 if (r_param->is_unsigned)
826 {
827 uint32 lval= (uint32)val;
828 longstore(buf, lval);
829 *r_param->error= (check_trunc_val != (double)lval);
830 } else {
831 int32 lval= (int32)val;
832 longstore(buf, lval);
833 *r_param->error= (check_trunc_val != (double)lval);
834 }
835 r_param->buffer_length= 4;
836 }
837 break;
838 case MYSQL_TYPE_LONGLONG:
839 {
840 if (r_param->is_unsigned)
841 {
842 ulonglong llval= (ulonglong)val;
843 longlongstore(buf, llval);
844 *r_param->error= (check_trunc_val != (double)llval);
845 } else {
846 longlong llval= (longlong)val;
847 longlongstore(buf, llval);
848 *r_param->error= (check_trunc_val != (double)llval);
849 }
850 r_param->buffer_length= 8;
851 }
852 break;
853 case MYSQL_TYPE_DOUBLE:
854 {
855 double dval= (double)val;
856 memcpy(buf, &dval, sizeof(double));
857 r_param->buffer_length= 8;
858 }
859 break;
860 default:
861 {
862 char buff[MAX_DOUBLE_STRING_REP_LENGTH];
863 size_t length;
864
865 length= MIN(MAX_DOUBLE_STRING_REP_LENGTH - 1, r_param->buffer_length);
866
867 if (field->decimals >= NOT_FIXED_DEC)
868 {
869 length= ma_gcvt(val, MY_GCVT_ARG_FLOAT, (int)length, buff, NULL);
870 }
871 else
872 {
873 length= ma_fcvt(val, field->decimals, buff, NULL);
874 }
875
876 /* check if ZEROFILL flag is active */
877 if (field->flags & ZEROFILL_FLAG)
878 {
879 /* enough space available ? */
880 if (field->length < length || field->length > MAX_DOUBLE_STRING_REP_LENGTH - 1)
881 break;
882 ma_bmove_upp(buff + field->length, buff + length, length);
883 /* coverity [bad_memset] */
884 memset((void*) buff, (int) '0', field->length - length);
885 length= field->length;
886 }
887
888 convert_froma_string(r_param, buff, length);
889 }
890 break;
891 }
892}
893
894static void convert_from_double(MYSQL_BIND *r_param, const MYSQL_FIELD *field, double val, int size __attribute__((unused)))
895{
896 double check_trunc_val= (val > 0) ? floor(val) : -floor(-val);
897 char *buf= (char *)r_param->buffer;
898 switch (r_param->buffer_type)
899 {
900 case MYSQL_TYPE_TINY:
901 *buf= (r_param->is_unsigned) ? (uint8)val : (int8)val;
902 *r_param->error= check_trunc_val != (r_param->is_unsigned ? (double)((uint8)*buf) :
903 (double)((int8)*buf));
904 r_param->buffer_length= 1;
905 break;
906 case MYSQL_TYPE_SHORT:
907 case MYSQL_TYPE_YEAR:
908 {
909 if (r_param->is_unsigned)
910 {
911 ushort sval= (ushort)val;
912 shortstore(buf, sval);
913 *r_param->error= check_trunc_val != (double)sval;
914 } else {
915 short sval= (short)val;
916 shortstore(buf, sval);
917 *r_param->error= check_trunc_val != (double)sval;
918 }
919 r_param->buffer_length= 2;
920 }
921 break;
922 case MYSQL_TYPE_LONG:
923 {
924 if (r_param->is_unsigned)
925 {
926 uint32 lval= (uint32)val;
927 longstore(buf, lval);
928 *r_param->error= (check_trunc_val != (double)lval);
929 } else {
930 int32 lval= (int32)val;
931 longstore(buf, lval);
932 *r_param->error= (check_trunc_val != (double)lval);
933 }
934 r_param->buffer_length= 4;
935 }
936 break;
937 case MYSQL_TYPE_LONGLONG:
938 {
939 if (r_param->is_unsigned)
940 {
941 ulonglong llval= (ulonglong)val;
942 longlongstore(buf, llval);
943 *r_param->error= (check_trunc_val != (double)llval);
944 } else {
945 longlong llval= (longlong)val;
946 longlongstore(buf, llval);
947 *r_param->error= (check_trunc_val != (double)llval);
948 }
949 r_param->buffer_length= 8;
950 }
951 break;
952 case MYSQL_TYPE_FLOAT:
953 {
954 float fval= (float)val;
955 memcpy(buf, &fval, sizeof(float));
956 *r_param->error= (*(float*)buf != fval);
957 r_param->buffer_length= 4;
958 }
959 break;
960 default:
961 {
962 char buff[MAX_DOUBLE_STRING_REP_LENGTH];
963 size_t length;
964
965 length= MIN(MAX_DOUBLE_STRING_REP_LENGTH - 1, r_param->buffer_length);
966
967 if (field->decimals >= NOT_FIXED_DEC)
968 {
969 length= ma_gcvt(val, MY_GCVT_ARG_DOUBLE, (int)length, buff, NULL);
970 }
971 else
972 {
973 length= ma_fcvt(val, field->decimals, buff, NULL);
974 }
975
976 /* check if ZEROFILL flag is active */
977 if (field->flags & ZEROFILL_FLAG)
978 {
979 /* enough space available ? */
980 if (field->length < length || field->length > MAX_DOUBLE_STRING_REP_LENGTH - 1)
981 break;
982 ma_bmove_upp(buff + field->length, buff + length, length);
983 /* coverity [bad_memset] */
984 memset((void*) buff, (int) '0', field->length - length);
985 length= field->length;
986 }
987 convert_froma_string(r_param, buff, length);
988 }
989 break;
990 }
991}
992
993
994/* {{{ ps_fetch_double */
995static
996void ps_fetch_double(MYSQL_BIND *r_param, const MYSQL_FIELD * field , unsigned char **row)
997{
998 switch (r_param->buffer_type)
999 {
1000 case MYSQL_TYPE_DOUBLE:
1001 {
1002 double *value= (double *)r_param->buffer;
1003 float8get(*value, *row);
1004 r_param->buffer_length= 8;
1005 }
1006 break;
1007 default:
1008 {
1009 double value;
1010 float8get(value, *row);
1011 convert_from_double(r_param, field, value, sizeof(double));
1012 }
1013 break;
1014 }
1015 (*row)+= 8;
1016}
1017/* }}} */
1018
1019/* {{{ ps_fetch_float */
1020static
1021void ps_fetch_float(MYSQL_BIND *r_param, const MYSQL_FIELD * field, unsigned char **row)
1022{
1023 switch(r_param->buffer_type)
1024 {
1025 case MYSQL_TYPE_FLOAT:
1026 {
1027 float *value= (float *)r_param->buffer;
1028 float4get(*value, *row);
1029 r_param->buffer_length= 4;
1030 *r_param->error= 0;
1031 }
1032 break;
1033 default:
1034 {
1035 float value;
1036 memcpy(&value, *row, sizeof(float));
1037 float4get(value, (char *)*row);
1038 convert_from_float(r_param, field, value, sizeof(float));
1039 }
1040 break;
1041 }
1042 (*row)+= 4;
1043}
1044/* }}} */
1045
1046static void convert_to_datetime(MYSQL_TIME *t, unsigned char **row, uint len, enum enum_field_types type)
1047{
1048 memset(t, 0, sizeof(MYSQL_TIME));
1049
1050 /* binary protocol for datetime:
1051 4-bytes: DATE
1052 7-bytes: DATE + TIME
1053 >7 bytes: DATE + TIME with second_part
1054 */
1055 if (len)
1056 {
1057 unsigned char *to= *row;
1058 int has_date= 0;
1059 uint offset= 7;
1060
1061 if (type == MYSQL_TYPE_TIME)
1062 {
1063 t->neg= to[0];
1064 t->day= (ulong) sint4korr(to + 1);
1065 t->time_type= MYSQL_TIMESTAMP_TIME;
1066 offset= 8;
1067 to++;
1068 } else
1069 {
1070 t->year= (uint) sint2korr(to);
1071 t->month= (uint) to[2];
1072 t->day= (uint) to[3];
1073 t->time_type= MYSQL_TIMESTAMP_DATE;
1074 if (type == MYSQL_TYPE_DATE)
1075 return;
1076 has_date= 1;
1077 }
1078
1079 if (len > 4)
1080 {
1081 t->hour= (uint) to[4];
1082 if (type == MYSQL_TYPE_TIME)
1083 t->hour+= t->day * 24;
1084 t->minute= (uint) to[5];
1085 t->second= (uint) to[6];
1086 if (has_date)
1087 t->time_type= MYSQL_TIMESTAMP_DATETIME;
1088 }
1089 if (len > offset)
1090 {
1091 t->second_part= (ulong)sint4korr(to+7);
1092 }
1093 }
1094}
1095
1096
1097/* {{{ ps_fetch_datetime */
1098static
1099void ps_fetch_datetime(MYSQL_BIND *r_param, const MYSQL_FIELD * field,
1100 unsigned char **row)
1101{
1102 MYSQL_TIME *t= (MYSQL_TIME *)r_param->buffer;
1103 unsigned int len= net_field_length(row);
1104
1105 switch (r_param->buffer_type) {
1106 case MYSQL_TYPE_DATETIME:
1107 case MYSQL_TYPE_TIMESTAMP:
1108 convert_to_datetime(t, row, len, field->type);
1109 break;
1110 case MYSQL_TYPE_DATE:
1111 convert_to_datetime(t, row, len, field->type);
1112 break;
1113 case MYSQL_TYPE_TIME:
1114 convert_to_datetime(t, row, len, field->type);
1115 t->year= t->day= t->month= 0;
1116 break;
1117 case MYSQL_TYPE_YEAR:
1118 {
1119 MYSQL_TIME tm;
1120 convert_to_datetime(&tm, row, len, field->type);
1121 shortstore(r_param->buffer, tm.year);
1122 break;
1123 }
1124 default:
1125 {
1126 char dtbuffer[60];
1127 MYSQL_TIME tm;
1128 size_t length;
1129 convert_to_datetime(&tm, row, len, field->type);
1130 /*
1131 if (tm.time_type== MYSQL_TIMESTAMP_TIME && tm.day)
1132 {
1133 tm.hour+= tm.day * 24;
1134 tm.day=0;
1135 }
1136*/
1137 switch(field->type) {
1138 case MYSQL_TYPE_DATE:
1139 length= sprintf(dtbuffer, "%04u-%02u-%02u", tm.year, tm.month, tm.day);
1140 break;
1141 case MYSQL_TYPE_TIME:
1142 length= sprintf(dtbuffer, "%s%02u:%02u:%02u", (tm.neg ? "-" : ""), tm.hour, tm.minute, tm.second);
1143 if (field->decimals && field->decimals <= 6)
1144 {
1145 char ms[8];
1146 sprintf(ms, ".%06lu", tm.second_part);
1147 if (field->decimals < 6)
1148 ms[field->decimals + 1]= 0;
1149 length+= strlen(ms);
1150 strcat(dtbuffer, ms);
1151 }
1152 break;
1153 case MYSQL_TYPE_DATETIME:
1154 case MYSQL_TYPE_TIMESTAMP:
1155 length= sprintf(dtbuffer, "%04u-%02u-%02u %02u:%02u:%02u", tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second);
1156 if (field->decimals && field->decimals <= 6)
1157 {
1158 char ms[8];
1159 sprintf(ms, ".%06lu", tm.second_part);
1160 if (field->decimals < 6)
1161 ms[field->decimals + 1]= 0;
1162 length+= strlen(ms);
1163 strcat(dtbuffer, ms);
1164 }
1165 break;
1166 default:
1167 dtbuffer[0]= 0;
1168 length= 0;
1169 break;
1170 }
1171 convert_froma_string(r_param, dtbuffer, length);
1172 break;
1173 }
1174 }
1175 (*row) += len;
1176}
1177/* }}} */
1178
1179/* {{{ ps_fetch_string */
1180static
1181void ps_fetch_string(MYSQL_BIND *r_param,
1182 const MYSQL_FIELD *field __attribute__((unused)),
1183 unsigned char **row)
1184{
1185 /* C-API differs from PHP. While PHP just converts string to string,
1186 C-API needs to convert the string to the defined type with in
1187 the result bind buffer.
1188 */
1189 ulong field_length= net_field_length(row);
1190
1191 convert_froma_string(r_param, (char *)*row, field_length);
1192 (*row) += field_length;
1193}
1194/* }}} */
1195
1196/* {{{ ps_fetch_bin */
1197static
1198void ps_fetch_bin(MYSQL_BIND *r_param,
1199 const MYSQL_FIELD *field,
1200 unsigned char **row)
1201{
1202 if (field->charsetnr == 63)
1203 {
1204 ulong field_length= *r_param->length= net_field_length(row);
1205 uchar *current_pos= (*row) + r_param->offset,
1206 *end= (*row) + field_length;
1207 size_t copylen= 0;
1208
1209 if (current_pos < end)
1210 {
1211 copylen= end - current_pos;
1212 if (r_param->buffer_length)
1213 memcpy(r_param->buffer, current_pos, MIN(copylen, r_param->buffer_length));
1214 }
1215 if (copylen < r_param->buffer_length &&
1216 (r_param->buffer_type == MYSQL_TYPE_STRING ||
1217 r_param->buffer_type == MYSQL_TYPE_JSON))
1218 ((char *)r_param->buffer)[copylen]= 0;
1219 *r_param->error= copylen > r_param->buffer_length;
1220 (*row)+= field_length;
1221 }
1222 else
1223 ps_fetch_string(r_param, field, row);
1224}
1225/* }}} */
1226
1227/* {{{ _mysqlnd_init_ps_subsystem */
1228void mysql_init_ps_subsystem(void)
1229{
1230 memset(mysql_ps_fetch_functions, 0, sizeof(mysql_ps_fetch_functions));
1231 mysql_ps_fetch_functions[MYSQL_TYPE_NULL].func= ps_fetch_null;
1232 mysql_ps_fetch_functions[MYSQL_TYPE_NULL].pack_len = 0;
1233 mysql_ps_fetch_functions[MYSQL_TYPE_NULL].max_len = 0;
1234
1235 mysql_ps_fetch_functions[MYSQL_TYPE_TINY].func = ps_fetch_int8;
1236 mysql_ps_fetch_functions[MYSQL_TYPE_TINY].pack_len = 1;
1237 mysql_ps_fetch_functions[MYSQL_TYPE_TINY].max_len = 4;
1238
1239 mysql_ps_fetch_functions[MYSQL_TYPE_SHORT].func = ps_fetch_int16;
1240 mysql_ps_fetch_functions[MYSQL_TYPE_SHORT].pack_len = 2;
1241 mysql_ps_fetch_functions[MYSQL_TYPE_SHORT].max_len = 6;
1242
1243 mysql_ps_fetch_functions[MYSQL_TYPE_YEAR].func = ps_fetch_int16;
1244 mysql_ps_fetch_functions[MYSQL_TYPE_YEAR].pack_len = 2;
1245 mysql_ps_fetch_functions[MYSQL_TYPE_YEAR].max_len = 6;
1246
1247 mysql_ps_fetch_functions[MYSQL_TYPE_INT24].func = ps_fetch_int32;
1248 mysql_ps_fetch_functions[MYSQL_TYPE_INT24].pack_len = 4;
1249 mysql_ps_fetch_functions[MYSQL_TYPE_INT24].max_len = 9;
1250
1251 mysql_ps_fetch_functions[MYSQL_TYPE_LONG].func = ps_fetch_int32;
1252 mysql_ps_fetch_functions[MYSQL_TYPE_LONG].pack_len = 4;
1253 mysql_ps_fetch_functions[MYSQL_TYPE_LONG].max_len = 11;
1254
1255 mysql_ps_fetch_functions[MYSQL_TYPE_LONGLONG].func = ps_fetch_int64;
1256 mysql_ps_fetch_functions[MYSQL_TYPE_LONGLONG].pack_len= 8;
1257 mysql_ps_fetch_functions[MYSQL_TYPE_LONGLONG].max_len = 21;
1258
1259 mysql_ps_fetch_functions[MYSQL_TYPE_FLOAT].func = ps_fetch_float;
1260 mysql_ps_fetch_functions[MYSQL_TYPE_FLOAT].pack_len = 4;
1261 mysql_ps_fetch_functions[MYSQL_TYPE_FLOAT].max_len = MAX_DOUBLE_STRING_REP_LENGTH;
1262
1263 mysql_ps_fetch_functions[MYSQL_TYPE_DOUBLE].func = ps_fetch_double;
1264 mysql_ps_fetch_functions[MYSQL_TYPE_DOUBLE].pack_len = 8;
1265 mysql_ps_fetch_functions[MYSQL_TYPE_DOUBLE].max_len = MAX_DOUBLE_STRING_REP_LENGTH;
1266
1267 mysql_ps_fetch_functions[MYSQL_TYPE_TIME].func = ps_fetch_datetime;
1268 mysql_ps_fetch_functions[MYSQL_TYPE_TIME].pack_len = MYSQL_PS_SKIP_RESULT_W_LEN;
1269 mysql_ps_fetch_functions[MYSQL_TYPE_TIME].max_len = 17;
1270
1271 mysql_ps_fetch_functions[MYSQL_TYPE_DATE].func = ps_fetch_datetime;
1272 mysql_ps_fetch_functions[MYSQL_TYPE_DATE].pack_len = MYSQL_PS_SKIP_RESULT_W_LEN;
1273 mysql_ps_fetch_functions[MYSQL_TYPE_DATE].max_len = 10;
1274
1275 mysql_ps_fetch_functions[MYSQL_TYPE_NEWDATE].func = ps_fetch_string;
1276 mysql_ps_fetch_functions[MYSQL_TYPE_NEWDATE].pack_len = MYSQL_PS_SKIP_RESULT_W_LEN;
1277 mysql_ps_fetch_functions[MYSQL_TYPE_NEWDATE].max_len = -1;
1278
1279 mysql_ps_fetch_functions[MYSQL_TYPE_DATETIME].func = ps_fetch_datetime;
1280 mysql_ps_fetch_functions[MYSQL_TYPE_DATETIME].pack_len= MYSQL_PS_SKIP_RESULT_W_LEN;
1281 mysql_ps_fetch_functions[MYSQL_TYPE_DATETIME].max_len = 30;
1282
1283 mysql_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].func = ps_fetch_datetime;
1284 mysql_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].pack_len= MYSQL_PS_SKIP_RESULT_W_LEN;
1285 mysql_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].max_len = 30;
1286
1287 mysql_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].func = ps_fetch_bin;
1288 mysql_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].pack_len= MYSQL_PS_SKIP_RESULT_STR;
1289 mysql_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].max_len = -1;
1290
1291 mysql_ps_fetch_functions[MYSQL_TYPE_BLOB].func = ps_fetch_bin;
1292 mysql_ps_fetch_functions[MYSQL_TYPE_BLOB].pack_len = MYSQL_PS_SKIP_RESULT_STR;
1293 mysql_ps_fetch_functions[MYSQL_TYPE_BLOB].max_len = -1;
1294
1295 mysql_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].func = ps_fetch_bin;
1296 mysql_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].pack_len= MYSQL_PS_SKIP_RESULT_STR;
1297 mysql_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].max_len = -1;
1298
1299 mysql_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].func = ps_fetch_bin;
1300 mysql_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].pack_len = MYSQL_PS_SKIP_RESULT_STR;
1301 mysql_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].max_len = -1;
1302
1303 mysql_ps_fetch_functions[MYSQL_TYPE_BIT].func = ps_fetch_bin;
1304 mysql_ps_fetch_functions[MYSQL_TYPE_BIT].pack_len = MYSQL_PS_SKIP_RESULT_STR;
1305 mysql_ps_fetch_functions[MYSQL_TYPE_BIT].max_len = -1;
1306
1307 mysql_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].func = ps_fetch_string;
1308 mysql_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].pack_len = MYSQL_PS_SKIP_RESULT_STR;
1309 mysql_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].max_len = -1;
1310
1311 mysql_ps_fetch_functions[MYSQL_TYPE_VARCHAR].func = ps_fetch_string;
1312 mysql_ps_fetch_functions[MYSQL_TYPE_VARCHAR].pack_len = MYSQL_PS_SKIP_RESULT_STR;
1313 mysql_ps_fetch_functions[MYSQL_TYPE_VARCHAR].max_len = -1;
1314
1315 mysql_ps_fetch_functions[MYSQL_TYPE_STRING].func = ps_fetch_string;
1316 mysql_ps_fetch_functions[MYSQL_TYPE_STRING].pack_len = MYSQL_PS_SKIP_RESULT_STR;
1317 mysql_ps_fetch_functions[MYSQL_TYPE_STRING].max_len = -1;
1318
1319 mysql_ps_fetch_functions[MYSQL_TYPE_JSON].func = ps_fetch_string;
1320 mysql_ps_fetch_functions[MYSQL_TYPE_JSON].pack_len = MYSQL_PS_SKIP_RESULT_STR;
1321 mysql_ps_fetch_functions[MYSQL_TYPE_JSON].max_len = -1;
1322
1323 mysql_ps_fetch_functions[MYSQL_TYPE_DECIMAL].func = ps_fetch_string;
1324 mysql_ps_fetch_functions[MYSQL_TYPE_DECIMAL].pack_len = MYSQL_PS_SKIP_RESULT_STR;
1325 mysql_ps_fetch_functions[MYSQL_TYPE_DECIMAL].max_len = -1;
1326
1327 mysql_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].func = ps_fetch_string;
1328 mysql_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].pack_len = MYSQL_PS_SKIP_RESULT_STR;
1329 mysql_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].max_len = -1;
1330
1331 mysql_ps_fetch_functions[MYSQL_TYPE_ENUM].func = ps_fetch_string;
1332 mysql_ps_fetch_functions[MYSQL_TYPE_ENUM].pack_len = MYSQL_PS_SKIP_RESULT_STR;
1333 mysql_ps_fetch_functions[MYSQL_TYPE_ENUM].max_len = -1;
1334
1335 mysql_ps_fetch_functions[MYSQL_TYPE_SET].func = ps_fetch_string;
1336 mysql_ps_fetch_functions[MYSQL_TYPE_SET].pack_len = MYSQL_PS_SKIP_RESULT_STR;
1337 mysql_ps_fetch_functions[MYSQL_TYPE_SET].max_len = -1;
1338
1339 mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].func = ps_fetch_string;
1340 mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].pack_len= MYSQL_PS_SKIP_RESULT_STR;
1341 mysql_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].max_len = -1;
1342
1343 mysql_ps_subsystem_initialized= 1;
1344}
1345/* }}} */
1346
1347
1348/*
1349 * Local variables:
1350 * tab-width: 4
1351 * c-basic-offset: 4
1352 * End:
1353 * vim600: noet sw=4 ts=4 fdm=marker
1354 * vim<600: noet sw=4 ts=4
1355 */
1356