1 /* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. 2 Copyright (c) 2014 MariaDB Foundation 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; version 2 of the License. 7 8 This program is distributed in the hope that it will be useful, 9 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License 14 along with this program; if not, write to the Free Software 15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ 16 17 #include "mariadb.h" 18 #include "item_inetfunc.h" 19 20 #include "my_net.h" 21 22 /////////////////////////////////////////////////////////////////////////// 23 24 static const int IN_ADDR_SIZE= sizeof (in_addr); 25 static const int IN6_ADDR_SIZE= sizeof (in6_addr); 26 static const int IN6_ADDR_NUM_WORDS= IN6_ADDR_SIZE / 2; 27 28 static const char HEX_DIGITS[]= "0123456789abcdef"; 29 30 /////////////////////////////////////////////////////////////////////////// 31 32 longlong Item_func_inet_aton::val_int() 33 { 34 DBUG_ASSERT(fixed); 35 36 uint byte_result= 0; 37 ulonglong result= 0; // We are ready for 64 bit addresses 38 const char *p,* end; 39 char c= '.'; // we mark c to indicate invalid IP in case length is 0 40 int dot_count= 0; 41 42 StringBuffer<36> tmp; 43 String *s= args[0]->val_str_ascii(&tmp); 44 45 if (!s) // If null value 46 goto err; 47 48 null_value= 0; 49 50 end= (p = s->ptr()) + s->length(); 51 while (p < end) 52 { 53 c= *p++; 54 int digit= (int) (c - '0'); 55 if (digit >= 0 && digit <= 9) 56 { 57 if ((byte_result= byte_result * 10 + digit) > 255) 58 goto err; // Wrong address 59 } 60 else if (c == '.') 61 { 62 dot_count++; 63 result= (result << 8) + (ulonglong) byte_result; 64 byte_result= 0; 65 } 66 else 67 goto err; // Invalid character 68 } 69 if (c != '.') // IP number can't end on '.' 70 { 71 /* 72 Attempt to support short forms of IP-addresses. It's however pretty 73 basic one comparing to the BSD support. 74 Examples: 75 127 -> 0.0.0.127 76 127.255 -> 127.0.0.255 77 127.256 -> NULL (should have been 127.0.1.0) 78 127.2.1 -> 127.2.0.1 79 */ 80 switch (dot_count) { 81 case 1: result<<= 8; /* Fall through */ 82 case 2: result<<= 8; /* Fall through */ 83 } 84 return (result << 8) + (ulonglong) byte_result; 85 } 86 87 err: 88 null_value=1; 89 return 0; 90 } 91 92 /////////////////////////////////////////////////////////////////////////// 93 94 String* Item_func_inet_ntoa::val_str(String* str) 95 { 96 DBUG_ASSERT(fixed); 97 98 ulonglong n= (ulonglong) args[0]->val_int(); 99 100 /* 101 We do not know if args[0] is NULL until we have called 102 some val function on it if args[0] is not a constant! 103 104 Also return null if n > 255.255.255.255 105 */ 106 if ((null_value= (args[0]->null_value || n > 0xffffffff))) 107 return 0; // Null value 108 109 str->set_charset(collation.collation); 110 str->length(0); 111 112 uchar buf[8]; 113 int4store(buf, n); 114 115 /* Now we can assume little endian. */ 116 117 char num[4]; 118 num[3]= '.'; 119 120 for (uchar *p= buf + 4; p-- > buf;) 121 { 122 uint c= *p; 123 uint n1, n2; // Try to avoid divisions 124 n1= c / 100; // 100 digits 125 c-= n1 * 100; 126 n2= c / 10; // 10 digits 127 c-= n2 * 10; // last digit 128 num[0]= (char) n1 + '0'; 129 num[1]= (char) n2 + '0'; 130 num[2]= (char) c + '0'; 131 uint length= (n1 ? 4 : n2 ? 3 : 2); // Remove pre-zero 132 uint dot_length= (p <= buf) ? 1 : 0; 133 (void) str->append(num + 4 - length, length - dot_length, 134 &my_charset_latin1); 135 } 136 137 return str; 138 } 139 140 /////////////////////////////////////////////////////////////////////////// 141 142 /** 143 Check the function argument, handle errors properly. 144 145 @return The function value. 146 */ 147 148 longlong Item_func_inet_bool_base::val_int() 149 { 150 DBUG_ASSERT(fixed); 151 152 // String argument expected 153 if (unlikely(args[0]->result_type() != STRING_RESULT)) 154 return 0; 155 156 String buffer; 157 String *arg_str= args[0]->val_str(&buffer); 158 159 if (unlikely(!arg_str)) // Out-of memory happened. error has been reported. 160 return 0; // Or: the underlying field is NULL 161 162 return calc_value(arg_str) ? 1 : 0; 163 } 164 165 /////////////////////////////////////////////////////////////////////////// 166 167 /** 168 Check the function argument, handle errors properly. 169 170 @param [out] buffer Buffer for string operations. 171 172 @return The function value. 173 */ 174 175 String *Item_func_inet_str_base::val_str_ascii(String *buffer) 176 { 177 DBUG_ASSERT(fixed); 178 179 // String argument expected 180 if (unlikely(args[0]->result_type() != STRING_RESULT)) 181 { 182 null_value= true; 183 return NULL; 184 } 185 186 StringBuffer<STRING_BUFFER_USUAL_SIZE> tmp; 187 String *arg_str= args[0]->val_str(&tmp); 188 if (unlikely(!arg_str)) 189 { 190 // Out-of memory happened. error has been reported. 191 // Or: the underlying field is NULL 192 null_value= true; 193 return NULL; 194 } 195 196 null_value= !calc_value(arg_str, buffer); 197 198 return unlikely(null_value) ? NULL : buffer; 199 } 200 201 /////////////////////////////////////////////////////////////////////////// 202 203 /** 204 Tries to convert given string to binary IPv4-address representation. 205 This is a portable alternative to inet_pton(AF_INET). 206 207 @param str String to convert. 208 @param str_len String length. 209 @param[out] ipv4_address Buffer to store IPv4-address. 210 211 @return Completion status. 212 @retval false Given string does not represent an IPv4-address. 213 @retval true The string has been converted successfully. 214 215 @note The problem with inet_pton() is that it treats leading zeros in 216 IPv4-part differently on different platforms. 217 */ 218 219 static bool str_to_ipv4(const char *str, size_t str_length, in_addr *ipv4_address) 220 { 221 if (str_length < 7) 222 { 223 DBUG_PRINT("error", ("str_to_ipv4(%.*s): " 224 "invalid IPv4 address: too short.", 225 (int) str_length, str)); 226 return false; 227 } 228 229 if (str_length > 15) 230 { 231 DBUG_PRINT("error", ("str_to_ipv4(%.*s): " 232 "invalid IPv4 address: too long.", 233 (int) str_length, str)); 234 return false; 235 } 236 237 unsigned char *ipv4_bytes= (unsigned char *) ipv4_address; 238 const char *p= str; 239 int byte_value= 0; 240 int chars_in_group= 0; 241 int dot_count= 0; 242 char c= 0; 243 244 while (((p - str) < (int)str_length) && *p) 245 { 246 c= *p++; 247 248 if (my_isdigit(&my_charset_latin1, c)) 249 { 250 ++chars_in_group; 251 252 if (chars_in_group > 3) 253 { 254 DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " 255 "too many characters in a group.", 256 (int) str_length, str)); 257 return false; 258 } 259 260 byte_value= byte_value * 10 + (c - '0'); 261 262 if (byte_value > 255) 263 { 264 DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " 265 "invalid byte value.", 266 (int) str_length, str)); 267 return false; 268 } 269 } 270 else if (c == '.') 271 { 272 if (chars_in_group == 0) 273 { 274 DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " 275 "too few characters in a group.", 276 (int) str_length, str)); 277 return false; 278 } 279 280 ipv4_bytes[dot_count]= (unsigned char) byte_value; 281 282 ++dot_count; 283 byte_value= 0; 284 chars_in_group= 0; 285 286 if (dot_count > 3) 287 { 288 DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " 289 "too many dots.", (int) str_length, str)); 290 return false; 291 } 292 } 293 else 294 { 295 DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " 296 "invalid character at pos %d.", 297 (int) str_length, str, (int) (p - str))); 298 return false; 299 } 300 } 301 302 if (c == '.') 303 { 304 DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " 305 "ending at '.'.", (int) str_length, str)); 306 return false; 307 } 308 309 if (dot_count != 3) 310 { 311 DBUG_PRINT("error", ("str_to_ipv4(%.*s): invalid IPv4 address: " 312 "too few groups.", 313 (int) str_length, str)); 314 return false; 315 } 316 317 ipv4_bytes[3]= (unsigned char) byte_value; 318 319 DBUG_PRINT("info", ("str_to_ipv4(%.*s): valid IPv4 address: %d.%d.%d.%d", 320 (int) str_length, str, 321 ipv4_bytes[0], ipv4_bytes[1], 322 ipv4_bytes[2], ipv4_bytes[3])); 323 return true; 324 } 325 326 /////////////////////////////////////////////////////////////////////////// 327 328 /** 329 Tries to convert given string to binary IPv6-address representation. 330 This is a portable alternative to inet_pton(AF_INET6). 331 332 @param str String to convert. 333 @param str_len String length. 334 @param[out] ipv6_address Buffer to store IPv6-address. 335 336 @return Completion status. 337 @retval false Given string does not represent an IPv6-address. 338 @retval true The string has been converted successfully. 339 340 @note The problem with inet_pton() is that it treats leading zeros in 341 IPv4-part differently on different platforms. 342 */ 343 344 static bool str_to_ipv6(const char *str, int str_length, in6_addr *ipv6_address) 345 { 346 if (str_length < 2) 347 { 348 DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: too short.", 349 str_length, str)); 350 return false; 351 } 352 353 if (str_length > 8 * 4 + 7) 354 { 355 DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: too long.", 356 str_length, str)); 357 return false; 358 } 359 360 memset(ipv6_address, 0, IN6_ADDR_SIZE); 361 362 const char *p= str; 363 364 if (*p == ':') 365 { 366 ++p; 367 368 if (*p != ':') 369 { 370 DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " 371 "can not start with ':x'.", str_length, str)); 372 return false; 373 } 374 } 375 376 char *ipv6_bytes= (char *) ipv6_address; 377 char *ipv6_bytes_end= ipv6_bytes + IN6_ADDR_SIZE; 378 char *dst= ipv6_bytes; 379 char *gap_ptr= NULL; 380 const char *group_start_ptr= p; 381 int chars_in_group= 0; 382 int group_value= 0; 383 384 while (((p - str) < str_length) && *p) 385 { 386 char c= *p++; 387 388 if (c == ':') 389 { 390 group_start_ptr= p; 391 392 if (!chars_in_group) 393 { 394 if (gap_ptr) 395 { 396 DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " 397 "too many gaps(::).", str_length, str)); 398 return false; 399 } 400 401 gap_ptr= dst; 402 continue; 403 } 404 405 if (!*p || ((p - str) >= str_length)) 406 { 407 DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " 408 "ending at ':'.", str_length, str)); 409 return false; 410 } 411 412 if (dst + 2 > ipv6_bytes_end) 413 { 414 DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " 415 "too many groups (1).", str_length, str)); 416 return false; 417 } 418 419 dst[0]= (unsigned char) (group_value >> 8) & 0xff; 420 dst[1]= (unsigned char) group_value & 0xff; 421 dst += 2; 422 423 chars_in_group= 0; 424 group_value= 0; 425 } 426 else if (c == '.') 427 { 428 if (dst + IN_ADDR_SIZE > ipv6_bytes_end) 429 { 430 DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " 431 "unexpected IPv4-part.", str_length, str)); 432 return false; 433 } 434 435 if (!str_to_ipv4(group_start_ptr, 436 str + str_length - group_start_ptr, 437 (in_addr *) dst)) 438 { 439 DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " 440 "invalid IPv4-part.", str_length, str)); 441 return false; 442 } 443 444 dst += IN_ADDR_SIZE; 445 chars_in_group= 0; 446 447 break; 448 } 449 else 450 { 451 const char *hdp= strchr(HEX_DIGITS, my_tolower(&my_charset_latin1, c)); 452 453 if (!hdp) 454 { 455 DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " 456 "invalid character at pos %d.", 457 str_length, str, (int) (p - str))); 458 return false; 459 } 460 461 if (chars_in_group >= 4) 462 { 463 DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " 464 "too many digits in group.", 465 str_length, str)); 466 return false; 467 } 468 469 group_value <<= 4; 470 group_value |= hdp - HEX_DIGITS; 471 472 DBUG_ASSERT(group_value <= 0xffff); 473 474 ++chars_in_group; 475 } 476 } 477 478 if (chars_in_group > 0) 479 { 480 if (dst + 2 > ipv6_bytes_end) 481 { 482 DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " 483 "too many groups (2).", str_length, str)); 484 return false; 485 } 486 487 dst[0]= (unsigned char) (group_value >> 8) & 0xff; 488 dst[1]= (unsigned char) group_value & 0xff; 489 dst += 2; 490 } 491 492 if (gap_ptr) 493 { 494 if (dst == ipv6_bytes_end) 495 { 496 DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " 497 "no room for a gap (::).", str_length, str)); 498 return false; 499 } 500 501 int bytes_to_move= (int)(dst - gap_ptr); 502 503 for (int i= 1; i <= bytes_to_move; ++i) 504 { 505 ipv6_bytes_end[-i]= gap_ptr[bytes_to_move - i]; 506 gap_ptr[bytes_to_move - i]= 0; 507 } 508 509 dst= ipv6_bytes_end; 510 } 511 512 if (dst < ipv6_bytes_end) 513 { 514 DBUG_PRINT("error", ("str_to_ipv6(%.*s): invalid IPv6 address: " 515 "too few groups.", str_length, str)); 516 return false; 517 } 518 519 return true; 520 } 521 522 /////////////////////////////////////////////////////////////////////////// 523 524 /** 525 Converts IPv4-binary-address to a string. This function is a portable 526 alternative to inet_ntop(AF_INET). 527 528 @param[in] ipv4 IPv4-address data (byte array) 529 @param[out] str A buffer to store string representation of IPv4-address. 530 It must be at least of INET_ADDRSTRLEN. 531 532 @note The problem with inet_ntop() is that it is available starting from 533 Windows Vista, but the minimum supported version is Windows 2000. 534 */ 535 536 static void ipv4_to_str(const in_addr *ipv4, char *str) 537 { 538 const unsigned char *ipv4_bytes= (const unsigned char *) ipv4; 539 540 sprintf(str, "%d.%d.%d.%d", 541 ipv4_bytes[0], ipv4_bytes[1], ipv4_bytes[2], ipv4_bytes[3]); 542 } 543 /////////////////////////////////////////////////////////////////////////// 544 545 /** 546 Converts IPv6-binary-address to a string. This function is a portable 547 alternative to inet_ntop(AF_INET6). 548 549 @param[in] ipv6 IPv6-address data (byte array) 550 @param[out] str A buffer to store string representation of IPv6-address. 551 It must be at least of INET6_ADDRSTRLEN. 552 553 @note The problem with inet_ntop() is that it is available starting from 554 Windows Vista, but out the minimum supported version is Windows 2000. 555 */ 556 557 static void ipv6_to_str(const in6_addr *ipv6, char *str) 558 { 559 struct Region 560 { 561 int pos; 562 int length; 563 }; 564 565 const unsigned char *ipv6_bytes= (const unsigned char *) ipv6; 566 567 // 1. Translate IPv6-address bytes to words. 568 // We can't just cast to short, because it's not guaranteed 569 // that sizeof (short) == 2. So, we have to make a copy. 570 571 uint16 ipv6_words[IN6_ADDR_NUM_WORDS]; 572 573 for (int i= 0; i < IN6_ADDR_NUM_WORDS; ++i) 574 ipv6_words[i]= (ipv6_bytes[2 * i] << 8) + ipv6_bytes[2 * i + 1]; 575 576 // 2. Find "the gap" -- longest sequence of zeros in IPv6-address. 577 578 Region gap= { -1, -1 }; 579 580 { 581 Region rg= { -1, -1 }; 582 583 for (int i = 0; i < IN6_ADDR_NUM_WORDS; ++i) 584 { 585 if (ipv6_words[i] != 0) 586 { 587 if (rg.pos >= 0) 588 { 589 if (rg.length > gap.length) 590 gap= rg; 591 592 rg.pos= -1; 593 rg.length= -1; 594 } 595 } 596 else 597 { 598 if (rg.pos >= 0) 599 { 600 ++rg.length; 601 } 602 else 603 { 604 rg.pos= i; 605 rg.length= 1; 606 } 607 } 608 } 609 610 if (rg.pos >= 0) 611 { 612 if (rg.length > gap.length) 613 gap= rg; 614 } 615 } 616 617 // 3. Convert binary data to string. 618 619 char *p= str; 620 621 for (int i = 0; i < IN6_ADDR_NUM_WORDS; ++i) 622 { 623 if (i == gap.pos) 624 { 625 // We're at the gap position. We should put trailing ':' and jump to 626 // the end of the gap. 627 628 if (i == 0) 629 { 630 // The gap starts from the beginning of the data -- leading ':' 631 // should be put additionally. 632 633 *p= ':'; 634 ++p; 635 } 636 637 *p= ':'; 638 ++p; 639 640 i += gap.length - 1; 641 } 642 else if (i == 6 && gap.pos == 0 && 643 (gap.length == 6 || // IPv4-compatible 644 (gap.length == 5 && ipv6_words[5] == 0xffff) // IPv4-mapped 645 )) 646 { 647 // The data represents either IPv4-compatible or IPv4-mapped address. 648 // The IPv6-part (zeros or zeros + ffff) has been already put into 649 // the string (str). Now it's time to dump IPv4-part. 650 651 ipv4_to_str((const in_addr *) (ipv6_bytes + 12), p); 652 return; 653 } 654 else 655 { 656 // Usual IPv6-address-field. Print it out using lower-case 657 // hex-letters without leading zeros (recommended IPv6-format). 658 // 659 // If it is not the last field, append closing ':'. 660 661 p += sprintf(p, "%x", ipv6_words[i]); 662 663 if (i != IN6_ADDR_NUM_WORDS - 1) 664 { 665 *p= ':'; 666 ++p; 667 } 668 } 669 } 670 671 *p= 0; 672 } 673 674 /////////////////////////////////////////////////////////////////////////// 675 676 /** 677 Converts IP-address-string to IP-address-data. 678 679 @param arg IP-address-string. 680 @param [out] buffer Buffer to store IP-address-data. 681 682 @return Completion status. 683 @retval false Given string does not represent an IP-address. 684 @retval true The string has been converted successfully. 685 */ 686 687 bool Item_func_inet6_aton::calc_value(const String *arg, String *buffer) 688 { 689 // ipv4-string -> varbinary(4) 690 // ipv6-string -> varbinary(16) 691 692 in_addr ipv4_address; 693 in6_addr ipv6_address; 694 695 if (str_to_ipv4(arg->ptr(), arg->length(), &ipv4_address)) 696 { 697 buffer->length(0); 698 buffer->append((char *) &ipv4_address, sizeof (in_addr), &my_charset_bin); 699 700 return true; 701 } 702 703 if (str_to_ipv6(arg->ptr(), arg->length(), &ipv6_address)) 704 { 705 buffer->length(0); 706 buffer->append((char *) &ipv6_address, sizeof (in6_addr), &my_charset_bin); 707 708 return true; 709 } 710 711 return false; 712 } 713 714 /////////////////////////////////////////////////////////////////////////// 715 716 /** 717 Converts IP-address-data to IP-address-string. 718 719 @param arg IP-address-data. 720 @param [out] buffer Buffer to store IP-address-string. 721 722 @return Completion status. 723 @retval false The argument does not correspond to IP-address. 724 @retval true The string has been converted successfully. 725 */ 726 727 bool Item_func_inet6_ntoa::calc_value(const String *arg, String *buffer) 728 { 729 if (arg->charset() != &my_charset_bin) 730 return false; 731 732 if ((int) arg->length() == IN_ADDR_SIZE) 733 { 734 char str[INET_ADDRSTRLEN]; 735 736 ipv4_to_str((const in_addr *) arg->ptr(), str); 737 738 buffer->length(0); 739 buffer->append(str, (uint32) strlen(str), &my_charset_latin1); 740 741 return true; 742 } 743 else if ((int) arg->length() == IN6_ADDR_SIZE) 744 { 745 char str[INET6_ADDRSTRLEN]; 746 747 ipv6_to_str((const in6_addr *) arg->ptr(), str); 748 749 buffer->length(0); 750 buffer->append(str, (uint32) strlen(str), &my_charset_latin1); 751 752 return true; 753 } 754 755 DBUG_PRINT("info", 756 ("INET6_NTOA(): varbinary(4) or varbinary(16) expected.")); 757 return false; 758 } 759 760 /////////////////////////////////////////////////////////////////////////// 761 762 /** 763 Checks if the passed string represents an IPv4-address. 764 765 @param arg The string to check. 766 767 @return Check status. 768 @retval false The passed string does not represent an IPv4-address. 769 @retval true The passed string represents an IPv4-address. 770 */ 771 772 bool Item_func_is_ipv4::calc_value(const String *arg) 773 { 774 in_addr ipv4_address; 775 776 return str_to_ipv4(arg->ptr(), arg->length(), &ipv4_address); 777 } 778 779 /////////////////////////////////////////////////////////////////////////// 780 781 /** 782 Checks if the passed string represents an IPv6-address. 783 784 @param arg The string to check. 785 786 @return Check status. 787 @retval false The passed string does not represent an IPv6-address. 788 @retval true The passed string represents an IPv6-address. 789 */ 790 791 bool Item_func_is_ipv6::calc_value(const String *arg) 792 { 793 in6_addr ipv6_address; 794 795 return str_to_ipv6(arg->ptr(), arg->length(), &ipv6_address); 796 } 797 798 /////////////////////////////////////////////////////////////////////////// 799 800 /** 801 Checks if the passed IPv6-address is an IPv4-compat IPv6-address. 802 803 @param arg The IPv6-address to check. 804 805 @return Check status. 806 @retval false The passed IPv6-address is not an IPv4-compatible IPv6-address. 807 @retval true The passed IPv6-address is an IPv4-compatible IPv6-address. 808 */ 809 810 bool Item_func_is_ipv4_compat::calc_value(const String *arg) 811 { 812 if ((int) arg->length() != IN6_ADDR_SIZE || arg->charset() != &my_charset_bin) 813 return false; 814 815 return IN6_IS_ADDR_V4COMPAT((struct in6_addr *) arg->ptr()); 816 } 817 818 /////////////////////////////////////////////////////////////////////////// 819 820 /** 821 Checks if the passed IPv6-address is an IPv4-mapped IPv6-address. 822 823 @param arg The IPv6-address to check. 824 825 @return Check status. 826 @retval false The passed IPv6-address is not an IPv4-mapped IPv6-address. 827 @retval true The passed IPv6-address is an IPv4-mapped IPv6-address. 828 */ 829 830 bool Item_func_is_ipv4_mapped::calc_value(const String *arg) 831 { 832 if ((int) arg->length() != IN6_ADDR_SIZE || arg->charset() != &my_charset_bin) 833 return false; 834 835 return IN6_IS_ADDR_V4MAPPED((struct in6_addr *) arg->ptr()); 836 } 837