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