Skip to content

Commit

Permalink
SQL: Implement CAST between STRING and IP (#34949)
Browse files Browse the repository at this point in the history
This allows comparison between IP fields and STRING input
from the user where automatic conversion is not yet supported (e.g.: for IN)

Closes: #34799
  • Loading branch information
Marios Trivyzas committed Oct 29, 2018
1 parent 731e48b commit 8d7889d
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 2 deletions.
Expand Up @@ -388,6 +388,8 @@ public DataType visitPrimitiveDataType(PrimitiveDataTypeContext ctx) {
case "varchar":
case "string":
return DataType.KEYWORD;
case "ip":
return DataType.IP;
default:
throw new ParsingException(source(ctx), "Does not recognize type {}", type);
}
Expand Down
Expand Up @@ -6,6 +6,7 @@
package org.elasticsearch.xpack.sql.type;

import org.elasticsearch.common.Booleans;
import org.elasticsearch.common.network.InetAddresses;
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
Expand Down Expand Up @@ -117,6 +118,8 @@ private static Conversion conversion(DataType from, DataType to) {
case KEYWORD:
case TEXT:
return conversionToString(from);
case IP:
return conversionToIp(from);
case LONG:
return conversionToLong(from);
case INTEGER:
Expand Down Expand Up @@ -146,6 +149,13 @@ private static Conversion conversionToString(DataType from) {
return Conversion.OTHER_TO_STRING;
}

private static Conversion conversionToIp(DataType from) {
if (from.isString()) {
return Conversion.STRING_TO_IP;
}
return null;
}

private static Conversion conversionToLong(DataType from) {
if (from.isRational) {
return Conversion.RATIONAL_TO_LONG;
Expand Down Expand Up @@ -409,7 +419,14 @@ public enum Conversion {
STRING_TO_BOOLEAN(fromString(DataTypeConversion::convertToBoolean, "Boolean")),
DATE_TO_BOOLEAN(fromDate(value -> value != 0)),

BOOL_TO_LONG(fromBool(value -> value ? 1L : 0L));
BOOL_TO_LONG(fromBool(value -> value ? 1L : 0L)),

STRING_TO_IP(o -> {
if (!InetAddresses.isInetAddress(o.toString())) {
throw new SqlIllegalArgumentException( "[" + o + "] is not a valid IPv4 or IPv6 address");
}
return o;
});

private final Function<Object, Object> converter;

Expand Down Expand Up @@ -464,4 +481,4 @@ public static DataType asInteger(DataType dataType) {

return dataType.isInteger ? dataType : LONG;
}
}
}
Expand Up @@ -7,10 +7,13 @@

import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
import org.elasticsearch.xpack.sql.expression.Literal;
import org.elasticsearch.xpack.sql.type.DataTypeConversion.Conversion;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;

import static org.elasticsearch.xpack.sql.tree.Location.EMPTY;

public class DataTypeConversionTests extends ESTestCase {
public void testConversionToString() {
Conversion conversion = DataTypeConversion.conversionFor(DataType.DOUBLE, DataType.KEYWORD);
Expand Down Expand Up @@ -252,4 +255,19 @@ public void testConversionToUnsupported() {
() -> DataTypeConversion.conversionFor(DataType.INTEGER, DataType.UNSUPPORTED));
assertEquals("cannot convert from [INTEGER] to [UNSUPPORTED]", e.getMessage());
}

public void testStringToIp() {
Conversion conversion = DataTypeConversion.conversionFor(DataType.KEYWORD, DataType.IP);
assertNull(conversion.convert(null));
assertEquals("192.168.1.1", conversion.convert("192.168.1.1"));
Exception e = expectThrows(SqlIllegalArgumentException.class, () -> conversion.convert("10.1.1.300"));
assertEquals("[10.1.1.300] is not a valid IPv4 or IPv6 address", e.getMessage());
}

public void testIpToString() {
Conversion ipToString = DataTypeConversion.conversionFor(DataType.IP, DataType.KEYWORD);
assertEquals("10.0.0.1", ipToString.convert(new Literal(EMPTY, "10.0.0.1", DataType.IP)));
Conversion stringToIp = DataTypeConversion.conversionFor(DataType.KEYWORD, DataType.IP);
assertEquals("10.0.0.1", ipToString.convert(stringToIp.convert(Literal.of(EMPTY, "10.0.0.1"))));
}
}
20 changes: 20 additions & 0 deletions x-pack/qa/sql/src/main/resources/ip.csv-spec
Expand Up @@ -72,6 +72,26 @@ SELECT id, client_ip, dest_ip FROM logs WHERE client_ip = '10.0.1.166' ORDER BY
34 |10.0.1.166 |2001:cafe::ff07:bdcc:bc59:ff9e
;

filterExactMatchIpv4WithIn_CastAsIP
SELECT id, client_ip, dest_ip FROM logs WHERE dest_ip IN (CAST('172.16.1.1' AS IP), CAST('2001:cafe::13e1:16fc:8726:1bf8' AS IP)) ORDER BY id DESC LIMIT 3;

id | client_ip | dest_ip
---------------+---------------+------------------------------
100 |10.0.0.129 |172.16.1.1
78 |10.0.1.199 |2001:cafe::13e1:16fc:8726:1bf8
69 |10.0.1.166 |2001:cafe::13e1:16fc:8726:1bf8
;

filterExactMatchIpv4WithIn_CastAsString
SELECT id, client_ip, dest_ip FROM logs WHERE CAST(dest_ip AS STRING) IN ('172.16.1.1', '2001:cafe::13e1:16fc:8726:1bf8') ORDER BY id DESC LIMIT 3;

id | client_ip | dest_ip
---------------+---------------+------------------------------
100 |10.0.0.129 |172.16.1.1
78 |10.0.1.199 |2001:cafe::13e1:16fc:8726:1bf8
69 |10.0.1.166 |2001:cafe::13e1:16fc:8726:1bf8
;

filterExactMatchIpv6
SELECT id, client_ip, dest_ip FROM logs WHERE dest_ip = 'fe80::86ba:3bff:fe05:c3f3' ORDER BY id LIMIT 10;

Expand Down

0 comments on commit 8d7889d

Please sign in to comment.