1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
|
/* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2014 MariaDB Foundation
Copyright (c) 2019 MariaDB Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
#define MYSQL_SERVER
#include "mariadb.h"
#include "item_inetfunc.h"
#include "sql_type_inet.h"
///////////////////////////////////////////////////////////////////////////
longlong Item_func_inet_aton::val_int()
{
DBUG_ASSERT(fixed());
uint byte_result= 0;
ulonglong result= 0; // We are ready for 64 bit addresses
const char *p,* end;
char c= '.'; // we mark c to indicate invalid IP in case length is 0
int dot_count= 0;
StringBuffer<36> tmp;
String *s= args[0]->val_str_ascii(&tmp);
if (!s) // If null value
goto err;
null_value= 0;
end= (p = s->ptr()) + s->length();
while (p < end)
{
c= *p++;
int digit= (int) (c - '0');
if (digit >= 0 && digit <= 9)
{
if ((byte_result= byte_result * 10 + digit) > 255)
goto err; // Wrong address
}
else if (c == '.')
{
dot_count++;
result= (result << 8) + (ulonglong) byte_result;
byte_result= 0;
}
else
goto err; // Invalid character
}
if (c != '.') // IP number can't end on '.'
{
/*
Attempt to support short forms of IP-addresses. It's however pretty
basic one comparing to the BSD support.
Examples:
127 -> 0.0.0.127
127.255 -> 127.0.0.255
127.256 -> NULL (should have been 127.0.1.0)
127.2.1 -> 127.2.0.1
*/
switch (dot_count) {
case 1: result<<= 8; /* Fall through */
case 2: result<<= 8; /* Fall through */
}
return (result << 8) + (ulonglong) byte_result;
}
err:
null_value=1;
return 0;
}
String* Item_func_inet_ntoa::val_str(String* str)
{
DBUG_ASSERT(fixed());
ulonglong n= (ulonglong) args[0]->val_int();
/*
We do not know if args[0] is NULL until we have called
some val function on it if args[0] is not a constant!
Also return null if n > 255.255.255.255
*/
if ((null_value= (args[0]->null_value || n > 0xffffffff)))
return 0; // Null value
str->set_charset(collation.collation);
str->length(0);
uchar buf[8];
int4store(buf, n);
/* Now we can assume little endian. */
char num[4];
num[3]= '.';
for (uchar *p= buf + 4; p-- > buf;)
{
uint c= *p;
uint n1, n2; // Try to avoid divisions
n1= c / 100; // 100 digits
c-= n1 * 100;
n2= c / 10; // 10 digits
c-= n2 * 10; // last digit
num[0]= (char) n1 + '0';
num[1]= (char) n2 + '0';
num[2]= (char) c + '0';
uint length= (n1 ? 4 : n2 ? 3 : 2); // Remove pre-zero
uint dot_length= (p <= buf) ? 1 : 0;
(void) str->append(num + 4 - length, length - dot_length,
&my_charset_latin1);
}
return str;
}
///////////////////////////////////////////////////////////////////////////
/**
Converts IP-address-string to IP-address-data.
ipv4-string -> varbinary(4)
ipv6-string -> varbinary(16)
@return Completion status.
@retval NULL Given string does not represent an IP-address.
@retval !NULL The string has been converted sucessfully.
*/
String *Item_func_inet6_aton::val_str(String *buffer)
{
DBUG_ASSERT(fixed());
Ascii_ptr_and_buffer<STRING_BUFFER_USUAL_SIZE> tmp(args[0]);
if ((null_value= tmp.is_null()))
return NULL;
Type_handler_inet4::Fbt_null ipv4(*tmp.string());
if (!ipv4.is_null())
{
ipv4.to_binary(buffer);
return buffer;
}
Type_handler_inet6::Fbt_null ipv6(*tmp.string());
if (!ipv6.is_null())
{
ipv6.to_binary(buffer);
return buffer;
}
null_value= true;
return NULL;
}
/**
Converts IP-address-data to IP-address-string.
*/
String *Item_func_inet6_ntoa::val_str_ascii(String *buffer)
{
DBUG_ASSERT(fixed());
// Binary string argument expected
if (unlikely(args[0]->result_type() != STRING_RESULT ||
args[0]->collation.collation != &my_charset_bin))
{
null_value= true;
return NULL;
}
String_ptr_and_buffer<STRING_BUFFER_USUAL_SIZE> tmp(args[0]);
if ((null_value= tmp.is_null()))
return NULL;
Type_handler_inet4::Fbt_null ipv4(static_cast<const Binary_string&>(*tmp.string()));
if (!ipv4.is_null())
{
ipv4.to_string(buffer);
return buffer;
}
Type_handler_inet6::Fbt_null ipv6(static_cast<const Binary_string&>(*tmp.string()));
if (!ipv6.is_null())
{
ipv6.to_string(buffer);
return buffer;
}
DBUG_PRINT("info", ("INET6_NTOA(): varbinary(4) or varbinary(16) expected."));
null_value= true;
return NULL;
}
/**
Checks if the passed string represents an IPv4-address.
*/
bool Item_func_is_ipv4::val_bool()
{
DBUG_ASSERT(fixed());
String_ptr_and_buffer<STRING_BUFFER_USUAL_SIZE> tmp(args[0]);
return !tmp.is_null() && !Type_handler_inet4::Fbt_null(*tmp.string()).is_null();
}
class IP6 : public Type_handler_inet6::Fbt_null
{
public:
IP6(Item* arg) : Type_handler_inet6::Fbt_null(arg) {}
bool is_v4compat() const
{
static_assert(sizeof(in6_addr) == IN6_ADDR_SIZE, "unexpected in6_addr size");
return IN6_IS_ADDR_V4COMPAT((struct in6_addr *) m_buffer);
}
bool is_v4mapped() const
{
static_assert(sizeof(in6_addr) == IN6_ADDR_SIZE, "unexpected in6_addr size");
return IN6_IS_ADDR_V4MAPPED((struct in6_addr *) m_buffer);
}
};
/**
Checks if the passed string represents an IPv6-address.
*/
bool Item_func_is_ipv6::val_bool()
{
DBUG_ASSERT(fixed());
String_ptr_and_buffer<STRING_BUFFER_USUAL_SIZE> tmp(args[0]);
return !tmp.is_null() && tmp.string()->strstr(STRING_WITH_LEN(":")) >= 0 &&
!Type_handler_inet6::Fbt_null(*tmp.string()).is_null();
}
/**
Checks if the passed IPv6-address is an IPv4-compat IPv6-address.
*/
bool Item_func_is_ipv4_compat::val_bool()
{
IP6 ip6(args[0]);
return !ip6.is_null() && ip6.is_v4compat();
}
/**
Checks if the passed IPv6-address is an IPv4-mapped IPv6-address.
*/
bool Item_func_is_ipv4_mapped::val_bool()
{
IP6 ip6(args[0]);
return !ip6.is_null() && ip6.is_v4mapped();
}
|