github.com/dolthub/go-mysql-server@v0.18.0/sql/expression/function/is_ip.go (about) 1 // Copyright 2020-2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package function 16 17 import ( 18 "fmt" 19 "net" 20 "strings" 21 22 "github.com/dolthub/go-mysql-server/sql/expression" 23 "github.com/dolthub/go-mysql-server/sql/types" 24 25 "github.com/dolthub/go-mysql-server/sql" 26 ) 27 28 type IsIPv4 struct { 29 expression.UnaryExpression 30 } 31 32 var _ sql.FunctionExpression = (*IsIPv4)(nil) 33 var _ sql.CollationCoercible = (*IsIPv4)(nil) 34 35 func NewIsIPv4(val sql.Expression) sql.Expression { 36 return &IsIPv4{expression.UnaryExpression{Child: val}} 37 } 38 39 // FunctionName implements sql.FunctionExpression 40 func (i *IsIPv4) FunctionName() string { 41 return "is_ipv4" 42 } 43 44 // Description implements sql.FunctionExpression 45 func (i *IsIPv4) Description() string { 46 return "returns whether argument is an IPv4 address." 47 } 48 49 func (i *IsIPv4) String() string { 50 return fmt.Sprintf("%s(%s)", i.FunctionName(), i.Child.String()) 51 } 52 53 func (i *IsIPv4) Type() sql.Type { return types.Boolean } 54 55 // CollationCoercibility implements the interface sql.CollationCoercible. 56 func (*IsIPv4) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 57 return sql.Collation_binary, 5 58 } 59 60 func (i *IsIPv4) WithChildren(children ...sql.Expression) (sql.Expression, error) { 61 if len(children) != 1 { 62 return nil, sql.ErrInvalidChildrenNumber.New(i, len(children), 1) 63 } 64 return NewIsIPv4(children[0]), nil 65 } 66 67 // Eval implements the Expression interface 68 func (i *IsIPv4) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 69 // Evaluate value 70 val, err := i.Child.Eval(ctx, row) 71 if err != nil { 72 return nil, err 73 } 74 75 // If null, return nul 76 if val == nil { 77 return nil, nil 78 } 79 80 // Must be of type string 81 switch val.(type) { 82 case string: 83 // Parse IP address, return false if not valid ip 84 ip := net.ParseIP(val.(string)) 85 if ip == nil { 86 return false, nil 87 } 88 89 // Check if ip address is valid IPv4 address 90 return ip.To4() != nil, nil 91 default: 92 return false, nil 93 } 94 } 95 96 type IsIPv6 struct { 97 expression.UnaryExpression 98 } 99 100 var _ sql.FunctionExpression = (*IsIPv6)(nil) 101 var _ sql.CollationCoercible = (*IsIPv6)(nil) 102 103 func NewIsIPv6(val sql.Expression) sql.Expression { 104 return &IsIPv6{expression.UnaryExpression{Child: val}} 105 } 106 107 // FunctionName implements sql.FunctionExpression 108 func (i *IsIPv6) FunctionName() string { 109 return "is_ipv6" 110 } 111 112 // Description implements sql.FunctionExpression 113 func (i *IsIPv6) Description() string { 114 return "returns whether argument is an IPv6 address." 115 } 116 117 func (i *IsIPv6) String() string { 118 return fmt.Sprintf("%s(%s)", i.FunctionName(), i.Child.String()) 119 } 120 121 func (i *IsIPv6) Type() sql.Type { return types.Boolean } 122 123 // CollationCoercibility implements the interface sql.CollationCoercible. 124 func (*IsIPv6) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 125 return sql.Collation_binary, 5 126 } 127 128 func (i *IsIPv6) WithChildren(children ...sql.Expression) (sql.Expression, error) { 129 if len(children) != 1 { 130 return nil, sql.ErrInvalidChildrenNumber.New(i, len(children), 1) 131 } 132 return NewIsIPv6(children[0]), nil 133 } 134 135 // Eval implements the Expression interface 136 func (i *IsIPv6) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 137 // Evaluate value 138 val, err := i.Child.Eval(ctx, row) 139 if err != nil { 140 return nil, err 141 } 142 143 // If null, return nul 144 if val == nil { 145 return nil, nil 146 } 147 148 // Must be of type string 149 switch val.(type) { 150 case string: 151 // Parse IP address, return false if not valid ip 152 ip := net.ParseIP(val.(string)) 153 if ip == nil { 154 return false, nil 155 } 156 157 // Check if ip address is valid IPv6 address 158 return ip.To16() != nil && (strings.Count(val.(string), ":") >= 2), nil 159 default: 160 return false, nil 161 } 162 } 163 164 type IsIPv4Compat struct { 165 expression.UnaryExpression 166 } 167 168 var _ sql.FunctionExpression = (*IsIPv4Compat)(nil) 169 var _ sql.CollationCoercible = (*IsIPv4Compat)(nil) 170 171 func NewIsIPv4Compat(val sql.Expression) sql.Expression { 172 return &IsIPv4Compat{expression.UnaryExpression{Child: val}} 173 } 174 175 // FunctionName implements sql.FunctionExpression 176 func (i *IsIPv4Compat) FunctionName() string { 177 return "is_ipv4_compat" 178 } 179 180 // Description implements sql.FunctionExpression 181 func (i *IsIPv4Compat) Description() string { 182 return "returns whether argument is an IPv4-compatible address." 183 } 184 185 func (i *IsIPv4Compat) String() string { 186 return fmt.Sprintf("%s(%s)", i.FunctionName(), i.Child.String()) 187 } 188 189 func (i *IsIPv4Compat) Type() sql.Type { return types.Boolean } 190 191 // CollationCoercibility implements the interface sql.CollationCoercible. 192 func (*IsIPv4Compat) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 193 return sql.Collation_binary, 5 194 } 195 196 func (i *IsIPv4Compat) WithChildren(children ...sql.Expression) (sql.Expression, error) { 197 if len(children) != 1 { 198 return nil, sql.ErrInvalidChildrenNumber.New(i, len(children), 1) 199 } 200 return NewIsIPv4Compat(children[0]), nil 201 } 202 203 // Eval implements the Expression interface 204 func (i *IsIPv4Compat) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 205 // Evaluate value 206 val, err := i.Child.Eval(ctx, row) 207 if err != nil { 208 return nil, err 209 } 210 211 // If null, return nul 212 if val == nil { 213 return nil, nil 214 } 215 216 // Expect to receive a hex encoded string 217 switch val.(type) { 218 case []byte: 219 // Must be of length 16 220 if len(val.([]byte)) != 16 { 221 return false, nil 222 } 223 224 // Check if first 12 bytes are all 0 225 for _, b := range val.([]byte)[:12] { 226 if b != 0 { 227 return false, nil 228 } 229 } 230 return true, nil 231 default: 232 return false, nil 233 } 234 } 235 236 type IsIPv4Mapped struct { 237 expression.UnaryExpression 238 } 239 240 var _ sql.FunctionExpression = (*IsIPv4Mapped)(nil) 241 var _ sql.CollationCoercible = (*IsIPv4Mapped)(nil) 242 243 func NewIsIPv4Mapped(val sql.Expression) sql.Expression { 244 return &IsIPv4Mapped{expression.UnaryExpression{Child: val}} 245 } 246 247 // FunctionName implements sql.FunctionExpression 248 func (i *IsIPv4Mapped) FunctionName() string { 249 return "is_ipv4_mapped" 250 } 251 252 // Description implements sql.FunctionExpression 253 func (i *IsIPv4Mapped) Description() string { 254 return "returns whether argument is an IPv4-mapped address." 255 } 256 257 func (i *IsIPv4Mapped) String() string { 258 return fmt.Sprintf("%s(%s)", i.FunctionName(), i.Child.String()) 259 } 260 261 func (i *IsIPv4Mapped) Type() sql.Type { return types.Boolean } 262 263 // CollationCoercibility implements the interface sql.CollationCoercible. 264 func (*IsIPv4Mapped) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 265 return sql.Collation_binary, 5 266 } 267 268 func (i *IsIPv4Mapped) WithChildren(children ...sql.Expression) (sql.Expression, error) { 269 if len(children) != 1 { 270 return nil, sql.ErrInvalidChildrenNumber.New(i, len(children), 1) 271 } 272 return NewIsIPv4Mapped(children[0]), nil 273 } 274 275 // Eval implements the Expression interface 276 func (i *IsIPv4Mapped) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 277 // Evaluate value 278 val, err := i.Child.Eval(ctx, row) 279 if err != nil { 280 return nil, err 281 } 282 283 // If null, return nul 284 if val == nil { 285 return nil, nil 286 } 287 288 // Expect to receive a hex encoded string 289 switch val.(type) { 290 case []byte: 291 // Must be of length 16 292 if len(val.([]byte)) != 16 { 293 return false, nil 294 } 295 296 // Check if first 10 bytes are all 0 297 for _, b := range val.([]byte)[:10] { 298 if b != 0 { 299 return false, nil 300 } 301 } 302 303 // Bytes 11 and 12 must be 0xFF 304 return val.([]byte)[10] == 0xFF && val.([]byte)[11] == 0xFF, nil 305 default: 306 return false, nil 307 } 308 }