SQL: Implement CAST between STRING and IP (#34949)
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
This commit is contained in:
parent
731e48beff
commit
8d7889d20c
|
@ -388,6 +388,8 @@ abstract class ExpressionBuilder extends IdentifierBuilder {
|
|||
case "varchar":
|
||||
case "string":
|
||||
return DataType.KEYWORD;
|
||||
case "ip":
|
||||
return DataType.IP;
|
||||
default:
|
||||
throw new ParsingException(source(ctx), "Does not recognize type {}", type);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -117,6 +118,8 @@ public abstract class DataTypeConversion {
|
|||
case KEYWORD:
|
||||
case TEXT:
|
||||
return conversionToString(from);
|
||||
case IP:
|
||||
return conversionToIp(from);
|
||||
case LONG:
|
||||
return conversionToLong(from);
|
||||
case INTEGER:
|
||||
|
@ -146,6 +149,13 @@ public abstract class DataTypeConversion {
|
|||
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;
|
||||
|
@ -409,7 +419,14 @@ public abstract class DataTypeConversion {
|
|||
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;
|
||||
|
||||
|
@ -464,4 +481,4 @@ public abstract class DataTypeConversion {
|
|||
|
||||
return dataType.isInteger ? dataType : LONG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,10 +7,13 @@ package org.elasticsearch.xpack.sql.type;
|
|||
|
||||
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);
|
||||
|
@ -252,4 +255,19 @@ public class DataTypeConversionTests extends ESTestCase {
|
|||
() -> 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"))));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue