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) - [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) by FirstName`
`Customers | summarize t = make_set_if(FirstName, Age > 10, 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 # July 17, 2022

View File

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