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