Support expressions as IP function arguments

This commit is contained in:
ltrk2 2022-07-19 09:52:54 -07:00 committed by Yong Wang
parent 8582543816
commit bfa2820985
2 changed files with 26 additions and 34 deletions

View File

@ -55,6 +55,15 @@ The config setting to allow modify dialect setting.
- [make_set_if()](https://docs.microsoft.com/en-us/azure/data-explorer/kusto/query/makesetif-aggfunction)
`Customers | summarize t = make_set_if(FirstName, Age > 10) by FirstName`
`Customers | summarize t = make_set_if(FirstName, Age > 10, 10) by FirstName`
# July XX, 2022
## IP functions
The following functions now support arbitrary expressions as their argument.
- [ipv4_is_private](https://docs.microsoft.com/en-us/azure/data-explorer/kusto/query/ipv4-is-privatefunction)
- [ipv4_is_in_range](https://docs.microsoft.com/en-us/azure/data-explorer/kusto/query/ipv4-is-in-range-function)
- [ipv4_netmask_suffix](https://docs.microsoft.com/en-us/azure/data-explorer/kusto/query/ipv4-netmask-suffix-function)
# July 17, 2022

View File

@ -22,21 +22,6 @@ namespace DB::ErrorCodes
extern const int SYNTAX_ERROR;
}
namespace
{
String trimQuotes(const String & str)
{
static constexpr auto QUOTE = '\'';
const auto first_index = str.find(QUOTE);
const auto last_index = str.rfind(QUOTE);
if (first_index == String::npos || last_index == String::npos)
throw DB::Exception("Syntax error, improper quotation: " + str, DB::ErrorCodes::SYNTAX_ERROR);
return str.substr(first_index + 1, last_index - first_index - 1);
}
}
namespace DB
{
@ -59,8 +44,7 @@ bool Ipv4IsInRange::convertImpl(String & out, IParser::Pos & pos)
++pos;
const auto ip_range = getConvertedArgument(function_name, pos);
const auto slash_index = ip_range.find('/');
out = std::format(slash_index == String::npos ? "{0} = {1}" : "isIPAddressInRange({0}, {1})", ip_address, ip_range);
out = std::format("isIPAddressInRange({0}, concat({1}, if(position({1}, '/') > 0, '', '/32')))", ip_address, ip_range);
return true;
}
@ -79,8 +63,9 @@ bool Ipv4IsPrivate::convertImpl(String & out, IParser::Pos & pos)
if (function_name.empty())
return false;
const auto ip_address = trimQuotes(getConvertedArgument(function_name, pos));
const auto slash_index = ip_address.find('/');
++pos;
const auto ip_address = getConvertedArgument(function_name, pos);
out += "or(";
for (int i = 0; i < std::ssize(PRIVATE_SUBNETS); ++i)
@ -88,14 +73,13 @@ bool Ipv4IsPrivate::convertImpl(String & out, IParser::Pos & pos)
out += i > 0 ? ", " : "";
const auto & subnet = PRIVATE_SUBNETS[i];
out += slash_index == String::npos
? std::format("isIPAddressInRange('{0}', '{1}')", ip_address, subnet)
: std::format(
"and(isIPAddressInRange(IPv4NumToString(tupleElement((IPv4CIDRToRange(toIPv4('{0}'), {1}) as range), 1)) as begin, '{2}'), "
"isIPAddressInRange(IPv4NumToString(tupleElement(range, 2)) as end, '{2}'))",
std::string_view(ip_address.c_str(), slash_index),
std::string_view(ip_address.c_str() + slash_index + 1, ip_address.length() - slash_index - 1),
subnet);
out += std::format(
"or(and(length(splitByChar('/', {0}) as tokens) = 1, isIPAddressInRange(tokens[1] as ip, '{1}')), "
"and(length(tokens) = 2, isIPAddressInRange(IPv4NumToString(tupleElement((IPv4CIDRToRange(toIPv4(ip), "
"if(isNull(toUInt8OrNull(tokens[-1]) as suffix), throwIf(true, 'Unable to parse suffix'), assumeNotNull(suffix))) as range), "
"1)) as begin, '{1}'), isIPAddressInRange(IPv4NumToString(tupleElement(range, 2)) as end, '{1}')))",
ip_address,
subnet);
}
out += ")";
@ -104,19 +88,18 @@ bool Ipv4IsPrivate::convertImpl(String & out, IParser::Pos & pos)
bool Ipv4NetmaskSuffix::convertImpl(String & out, IParser::Pos & pos)
{
static constexpr auto DEFAULT_NETMASK = 32;
const auto function_name = getKQLFunctionName(pos);
if (function_name.empty())
return false;
++pos;
const auto ip_range = trimQuotes(getConvertedArgument(function_name, pos));
const auto slash_index = ip_range.find('/');
const std::string_view ip_address(ip_range.c_str(), std::min(ip_range.length(), slash_index));
const auto netmask = slash_index == String::npos ? DEFAULT_NETMASK : std::strtol(ip_range.c_str() + slash_index + 1, nullptr, 10);
out = std::format("if(and(isIPv4String('{0}'), {1} between 1 and 32), {1}, null)", ip_address, netmask);
const auto ip_range = getConvertedArgument(function_name, pos);
out = std::format(
"if(length(splitByChar('/', {0}) as tokens) <= 2 and isIPv4String(tokens[1]), if(length(tokens) != 2, 32, "
"if((toInt8OrNull(tokens[-1]) as suffix) between 1 and 32, suffix, throwIf(true, 'Suffix must be between 1 and 32'))), "
"throwIf(true, 'Unable to recognize and IP address with or without a suffix'))",
ip_range);
return true;
}