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