From 72054031f1b3942627669fbb8ae1f9f668090da3 Mon Sep 17 00:00:00 2001 From: Yenda Li Date: Thu, 5 Dec 2024 15:43:37 -0800 Subject: [PATCH] Add ipprefix cast operators for ipaddr [2/n] (#11481) Summary: Pull Request resolved: https://github.com/facebookincubator/velox/pull/11481 Support casting ipprefix -> ipaddress, and ipaddress -> ipprefix. We just need one new helper function, tryIpPrefixLengthFromIPAddressType, which takes in int128_t, gets the ippaddress, and then we check if the ippaddress is ipv4 or ipv6 mapped. We return 32 for ipv4 and 128 for ipv6 mapped. Also applies suggestion from https://github.com/facebookincubator/velox/pull/11309/files Reviewed By: Yuhta Differential Revision: D65641994 fbshipit-source-id: aa43e1667affd73f263fedb33a101bc6aff7dea7 --- velox/docs/functions/presto/conversion.rst | 213 ++++++++++++++---- .../prestosql/tests/IPAddressCastTest.cpp | 25 ++ .../prestosql/tests/IPPrefixCastTest.cpp | 76 +++++++ .../prestosql/types/IPAddressType.cpp | 58 +++++ .../prestosql/types/IPPrefixType.cpp | 56 ++++- .../functions/prestosql/types/IPPrefixType.h | 21 +- 6 files changed, 386 insertions(+), 63 deletions(-) diff --git a/velox/docs/functions/presto/conversion.rst b/velox/docs/functions/presto/conversion.rst index b24117ae3068..a2d96843b325 100644 --- a/velox/docs/functions/presto/conversion.rst +++ b/velox/docs/functions/presto/conversion.rst @@ -30,7 +30,7 @@ are supported if the conversion of their element types are supported. In additio supported conversions to/from JSON are listed in :doc:`json`. .. list-table:: - :widths: 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 + :widths: 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 :header-rows: 1 * - @@ -49,6 +49,7 @@ supported conversions to/from JSON are listed in :doc:`json`. - interval day to second - decimal - ipaddress + - ipprefix * - tinyint - Y - Y @@ -58,13 +59,14 @@ supported conversions to/from JSON are listed in :doc:`json`. - Y - Y - Y - - + - - - - - - Y - - + - + - * - smallint - Y - Y @@ -74,13 +76,14 @@ supported conversions to/from JSON are listed in :doc:`json`. - Y - Y - Y - - + - - - - - - Y - - + - + - * - integer - Y - Y @@ -90,13 +93,14 @@ supported conversions to/from JSON are listed in :doc:`json`. - Y - Y - Y - - + - - - - - - Y - - + - + - * - bigint - Y - Y @@ -106,13 +110,14 @@ supported conversions to/from JSON are listed in :doc:`json`. - Y - Y - Y - - + - - - - - - Y - - + - + - * - boolean - Y - Y @@ -122,13 +127,14 @@ supported conversions to/from JSON are listed in :doc:`json`. - Y - Y - Y - - + - - - - - - Y - - + - + - * - real - Y - Y @@ -138,13 +144,14 @@ supported conversions to/from JSON are listed in :doc:`json`. - Y - Y - Y - - + - - - - - - Y - - + - + - * - double - Y - Y @@ -154,13 +161,14 @@ supported conversions to/from JSON are listed in :doc:`json`. - Y - Y - Y - - + - - - - - - Y - - + - + - * - varchar - Y - Y @@ -170,29 +178,31 @@ supported conversions to/from JSON are listed in :doc:`json`. - Y - Y - Y - - + - - Y - Y - Y - - Y - Y + - Y * - varbinary - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - Y + - * - timestamp - - @@ -202,13 +212,14 @@ supported conversions to/from JSON are listed in :doc:`json`. - - - Y - - + - - Y - Y - Y - - - - + - + - * - timestamp with time zone - - @@ -218,13 +229,14 @@ supported conversions to/from JSON are listed in :doc:`json`. - - - Y - - + - - Y - - Y - - - + - * - date - - @@ -234,13 +246,14 @@ supported conversions to/from JSON are listed in :doc:`json`. - - - Y - - + - - Y - Y - - - - + - * - interval day to second - - @@ -250,7 +263,8 @@ supported conversions to/from JSON are listed in :doc:`json`. - - - Y - - + - + - - - - @@ -266,30 +280,48 @@ supported conversions to/from JSON are listed in :doc:`json`. - Y - Y - Y - - + - - - - - - Y - + - * - ipaddress - - - - - - - - - - - - - - + - + - + - + - + - + - + - - Y - Y - - - - - - - - - + - + - + - Y + * - ipprefix + - + - + - + - + - + - + - + - Y + - + - + - + - + - + - + - Y + - Y Cast to Integral Types ---------------------- @@ -689,6 +721,33 @@ IPV4 mapped IPV6: SELECT cast(ipaddress '::ffff:ffff:ffff' as varchar); -- '255.255.255.255' +From IPPREFIX +^^^^^^^^^^^^^ + +Casting from IPPREFIX to VARCHAR returns a string formatted as *x.x.x.x/* for IPv4 formatted IPv6 addresses. + +For all other IPv6 addresses it will be formatted in compressed alternate form IPv6 defined in `RFC 4291#section-2.2 `_ +followed by */*. [`RFC 4291#section-2.3 `_] + +IPv4: + +:: + + SELECT cast(ipprefix '1.2.0.0/16' as varchar); -- '1.2.0.0/16' + +IPv6: + +:: + + SELECT cast(ipprefix '2001:db8::ff00:42:8329/128' as varchar); -- '2001:db8::ff00:42:8329/128' + SELECT cast(ipprefix '0:0:0:0:0:0:13.1.68.3/32' as varchar); -- '::/32' + +IPv4 mapped IPv6: + +:: + + SELECT cast(ipaddress '::ffff:ffff:0000/16' as varchar); -- '255.255.0.0/16' + Cast to VARBINARY ----------------- @@ -1036,6 +1095,8 @@ Invalid example Cast to IPADDRESS ----------------- +.. _ipaddress-from-varchar: + From VARCHAR ^^^^^^^^^^^^ @@ -1128,6 +1189,66 @@ Invalid examples: SELECT cast(from_hex('f000001100') as ipaddress); -- Invalid IP address binary length: 5 +From IPPREFIX +^^^^^^^^^^^^^ + +Returns the canonical(lowest) IPADDRESS in the subnet range. + +Examples: + +:: + + SELECT cast(ipprefix '1.2.3.4/24' as ipaddress) -- ipaddress '1.2.3.0' + SELECT cast(ipprefix '2001:db8::ff00:42:8329/64' as ipaddress) -- ipaddress '2001:db8::' + +Cast to IPPREFIX +---------------- + +From VARCHAR +^^^^^^^^^^^^ + +The IPPREFIX string must be in the form of */* as defined in `RFC 4291#section-2.3 `_. +The IPADDRESS portion of the IPPREFIX follows the same rules as casting +`IPADDRESS from VARCHAR <#ipaddress-from-varchar>`_. + +The prefix portion must be <= 32 if the IP is an IPv4 address or <= 128 for an IPv6 address. +As with IPADDRESS, any IPv6 address in the form of an IPv4 mapped IPv6 address will be +interpreted as an IPv4 address. Only the canonical(smallest) IP address will be stored +in the IPPREFIX. + +Examples: + +Valid examples: + +:: + + SELECT cast('2001:0db8:0000:0000:0000:ff00:0042:8329/32' as ipprefix); -- ipprefix '2001:0db8::/32' + SELECT cast('1.2.3.4/24' as ipprefix); -- ipprefix '1.2.3.0/24' + SELECT cast('::ffff:ffff:ffff/16' as ipprefix); -- ipprefix '255.255.0.0/16' + +Invalid examples: + +:: + + SELECT cast('2001:db8::1::1/1' as ipprefix); -- Cannot cast value to IPPREFIX: 2001:db8::1::1/1 + SELECT cast('2001:0db8:0000:0000:0000:ff00:0042:8329/129' as ipprefix); -- Cannot cast value to IPPREFIX: 2001:0db8:0000:0000:0000:ff00:0042:8329/129 + SELECT cast('2001:0db8:0000:0000:0000:ff00:0042:8329/-1' as ipprefix); -- Cannot cast value to IPPREFIX: 2001:0db8:0000:0000:0000:ff00:0042:8329/-1 + SELECT cast('255.2.3.4/33' as ipprefix); -- Cannot cast value to IPPREFIX: 255.2.3.4/33 + SELECT cast('::ffff:ffff:ffff/33' as ipprefix); -- Cannot cast value to IPPREFIX: ::ffff:ffff:ffff/33 + +From IPADDRESS +^^^^^^^^^^^^^^ + +Returns an IPPREFIX where the prefix length is the length of the entire IP address. +Prefix length for IPv4 is 32 and for IPv6 it is 128. + +Examples: + +:: + + SELECT cast(ipaddress '1.2.3.4' as ipprefix) -- ipprefix '1.2.3.4/32' + SELECT cast(ipaddress '2001:db8::ff00:42:8329' as ipprefix) -- ipprefix '2001:db8::ff00:42:8329/128' + Miscellaneous ------------- diff --git a/velox/functions/prestosql/tests/IPAddressCastTest.cpp b/velox/functions/prestosql/tests/IPAddressCastTest.cpp index a13ec9114e94..d211f031a3cf 100644 --- a/velox/functions/prestosql/tests/IPAddressCastTest.cpp +++ b/velox/functions/prestosql/tests/IPAddressCastTest.cpp @@ -43,6 +43,13 @@ class IPAddressCastTest : public functions::test::FunctionBaseTest { input); return result; } + + auto castToIPPrefixAndBackToIpVarchar( + const std::optional& input) { + return evaluateOnce( + "cast(cast(cast(cast(cast(cast(c0 as ipaddress) as ipprefix) as varchar) as ipprefix) as ipaddress) as varchar)", + input); + } }; int128_t stringToInt128(const std::string& value) { @@ -53,6 +60,24 @@ int128_t stringToInt128(const std::string& value) { return res; } +TEST_F(IPAddressCastTest, castToIPPrefix) { + EXPECT_EQ(castToIPPrefixAndBackToIpVarchar("1.2.3.4"), "1.2.3.4"); + EXPECT_EQ(castToIPPrefixAndBackToIpVarchar("::ffff:1.2.3.4"), "1.2.3.4"); + EXPECT_EQ(castToIPPrefixAndBackToIpVarchar("::ffff:102:304"), "1.2.3.4"); + EXPECT_EQ(castToIPPrefixAndBackToIpVarchar("192.168.0.0"), "192.168.0.0"); + EXPECT_EQ( + castToIPPrefixAndBackToIpVarchar( + "2001:0db8:0000:0000:0000:ff00:0042:8329"), + "2001:db8::ff00:42:8329"); + EXPECT_EQ( + castToIPPrefixAndBackToIpVarchar("2001:db8:0:0:1:0:0:1"), + "2001:db8::1:0:0:1"); + EXPECT_EQ(castToIPPrefixAndBackToIpVarchar("::1"), "::1"); + EXPECT_EQ( + castToIPPrefixAndBackToIpVarchar("2001:db8::ff00:42:8329"), + "2001:db8::ff00:42:8329"); +} + TEST_F(IPAddressCastTest, castToVarchar) { EXPECT_EQ(castToVarchar("::ffff:1.2.3.4"), "1.2.3.4"); EXPECT_EQ(castToVarchar("0:0:0:0:0:0:13.1.68.3"), "::13.1.68.3"); diff --git a/velox/functions/prestosql/tests/IPPrefixCastTest.cpp b/velox/functions/prestosql/tests/IPPrefixCastTest.cpp index c8c77f40ec52..9fcd711b3d2b 100644 --- a/velox/functions/prestosql/tests/IPPrefixCastTest.cpp +++ b/velox/functions/prestosql/tests/IPPrefixCastTest.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "velox/common/base/tests/GTestUtils.h" #include "velox/functions/prestosql/tests/utils/FunctionBaseTest.h" namespace facebook::velox::functions::prestosql { @@ -26,8 +27,83 @@ class IPPrefixTypeTest : public functions::test::FunctionBaseTest { "cast(cast(c0 as ipprefix) as varchar)", input); return result; } + + std::optional castToIpAddress( + const std::optional& input) { + return evaluateOnce( + "cast(cast(cast(c0 as ipprefix) as ipaddress) as varchar)", input); + } + + std::optional castFromIPAddress( + const std::optional& input) { + return evaluateOnce( + "cast(cast(cast(c0 as ipaddress) as ipprefix) as varchar)", input); + } }; +TEST_F(IPPrefixTypeTest, invalidIPPrefix) { + VELOX_ASSERT_THROW( + castToVarchar("facebook.com/32"), + "Cannot cast value to IPPREFIX: facebook.com"); + VELOX_ASSERT_THROW( + castToVarchar("localhost/32"), + "Cannot cast value to IPPREFIX: localhost"); + VELOX_ASSERT_THROW( + castToVarchar("2001:db8::1::1/128"), + "Cannot cast value to IPPREFIX: 2001:db8::1::1"); + VELOX_ASSERT_THROW( + castToVarchar("2001:zxy::1::1/128"), + "Cannot cast value to IPPREFIX: 2001:zxy::1::1"); + VELOX_ASSERT_THROW( + castToVarchar("789.1.1.1/32"), + "Cannot cast value to IPPREFIX: 789.1.1.1"); + VELOX_ASSERT_THROW( + castToVarchar("192.1.1.1"), "Cannot cast value to IPPREFIX: 192.1.1.1"); + VELOX_ASSERT_THROW( + castToVarchar("192.1.1.1/128"), + "Cannot cast value to IPPREFIX: 192.1.1.1/128"); + VELOX_ASSERT_THROW( + castToVarchar("192.1.1.1/-1"), + "Cannot cast value to IPPREFIX: 192.1.1.1/-1"); + VELOX_ASSERT_THROW( + castToVarchar("::ffff:ffff:ffff/33"), + "Cannot cast value to IPPREFIX: ::ffff:ffff:ffff/33"); + VELOX_ASSERT_THROW( + castToVarchar("::ffff:ffff:ffff/-1"), + "Cannot cast value to IPPREFIX: ::ffff:ffff:ffff/-1"); + VELOX_ASSERT_THROW( + castToVarchar("::/129"), "Cannot cast value to IPPREFIX: ::/129"); + VELOX_ASSERT_THROW( + castToVarchar("::/-1"), "Cannot cast value to IPPREFIX: ::/-1"); +} + +TEST_F(IPPrefixTypeTest, castFromIpAddress) { + EXPECT_EQ(castFromIPAddress(std::nullopt), std::nullopt); + EXPECT_EQ(castFromIPAddress("1.2.3.4"), "1.2.3.4/32"); + EXPECT_EQ(castFromIPAddress("::ffff:1.2.3.4"), "1.2.3.4/32"); + EXPECT_EQ(castFromIPAddress("::ffff:102:304"), "1.2.3.4/32"); + EXPECT_EQ(castFromIPAddress("192.168.0.0"), "192.168.0.0/32"); + EXPECT_EQ( + castFromIPAddress("2001:0db8:0000:0000:0000:ff00:0042:8329"), + "2001:db8::ff00:42:8329/128"); + EXPECT_EQ(castFromIPAddress("2001:db8:0:0:1:0:0:1"), "2001:db8::1:0:0:1/128"); + EXPECT_EQ(castFromIPAddress("::1"), "::1/128"); + EXPECT_EQ( + castFromIPAddress("2001:db8::ff00:42:8329"), + "2001:db8::ff00:42:8329/128"); + EXPECT_EQ(castFromIPAddress("2001:db8::"), "2001:db8::/128"); +} + +TEST_F(IPPrefixTypeTest, castToIpAddress) { + EXPECT_EQ(castToIpAddress(std::nullopt), std::nullopt); + EXPECT_EQ(castToIpAddress("1.2.3.4/32"), "1.2.3.4"); + EXPECT_EQ(castToIpAddress("1.2.3.4/24"), "1.2.3.0"); + EXPECT_EQ(castToIpAddress("::1/128"), "::1"); + EXPECT_EQ( + castToIpAddress("2001:db8::ff00:42:8329/128"), "2001:db8::ff00:42:8329"); + EXPECT_EQ(castToIpAddress("2001:db8::ff00:42:8329/64"), "2001:db8::"); +} + TEST_F(IPPrefixTypeTest, castToVarchar) { EXPECT_EQ(castToVarchar("::ffff:1.2.3.4/24"), "1.2.3.0/24"); EXPECT_EQ(castToVarchar("192.168.0.0/24"), "192.168.0.0/24"); diff --git a/velox/functions/prestosql/types/IPAddressType.cpp b/velox/functions/prestosql/types/IPAddressType.cpp index d9569c01f7a9..1b47fd3cc005 100644 --- a/velox/functions/prestosql/types/IPAddressType.cpp +++ b/velox/functions/prestosql/types/IPAddressType.cpp @@ -16,6 +16,8 @@ #include "velox/functions/prestosql/types/IPAddressType.h" #include "velox/expression/CastExpr.h" +#include "velox/expression/VectorWriters.h" +#include "velox/functions/prestosql/types/IPPrefixType.h" namespace facebook::velox { @@ -28,6 +30,11 @@ class IPAddressCastOperator : public exec::CastOperator { case TypeKind::VARBINARY: case TypeKind::VARCHAR: return true; + case TypeKind::ROW: + if (isIPPrefixType(other)) { + return true; + } + [[fallthrough]]; default: return false; } @@ -38,6 +45,11 @@ class IPAddressCastOperator : public exec::CastOperator { case TypeKind::VARBINARY: case TypeKind::VARCHAR: return true; + case TypeKind::ROW: + if (isIPPrefixType(other)) { + return true; + } + [[fallthrough]]; default: return false; } @@ -55,6 +67,9 @@ class IPAddressCastOperator : public exec::CastOperator { castFromString(input, context, rows, *result); } else if (input.typeKind() == TypeKind::VARBINARY) { castFromVarbinary(input, context, rows, *result); + } else if ( + input.typeKind() == TypeKind::ROW && isIPPrefixType(input.type())) { + castFromIPPrefix(input, context, rows, *result); } else { VELOX_UNSUPPORTED( "Cast from {} to IPAddress not supported", resultType->toString()); @@ -73,6 +88,9 @@ class IPAddressCastOperator : public exec::CastOperator { castToString(input, context, rows, *result); } else if (resultType->kind() == TypeKind::VARBINARY) { castToVarbinary(input, context, rows, *result); + } else if ( + resultType->kind() == TypeKind::ROW && isIPPrefixType(resultType)) { + castToIPPrefix(input, context, rows, *result); } else { VELOX_UNSUPPORTED( "Cast from IPAddress to {} not supported", resultType->toString()); @@ -155,6 +173,46 @@ class IPAddressCastOperator : public exec::CastOperator { }); } + static void castToIPPrefix( + const BaseVector& input, + exec::EvalCtx& context, + const SelectivityVector& rows, + BaseVector& result) { + auto* rowVectorResult = result.as(); + auto intIpAddrVec = + rowVectorResult->childAt(0)->asChecked>(); + auto intPrefixVec = + rowVectorResult->childAt(1)->asChecked>(); + + DecodedVector decoded(input, rows); + context.applyToSelectedNoThrow(rows, [&](auto row) { + const auto ipAddrVal = decoded.valueAt(row); + const auto tryPrefixLength = + ipaddress::tryIpPrefixLengthFromIPAddressType(ipAddrVal); + if (FOLLY_UNLIKELY(tryPrefixLength.hasError())) { + context.setStatus(row, std::move(tryPrefixLength).error()); + return; + } + + intIpAddrVec->set(row, ipAddrVal); + intPrefixVec->set(row, tryPrefixLength.value()); + }); + } + + static void castFromIPPrefix( + const BaseVector& input, + exec::EvalCtx& context, + const SelectivityVector& rows, + BaseVector& result) { + auto* flatResult = result.as>(); + const auto* ipprefix = input.as(); + const auto* ipaddr = ipprefix->childAt(ipaddress::kIpRowIndex) + ->asChecked>(); + + context.applyToSelectedNoThrow( + rows, [&](auto row) { flatResult->set(row, ipaddr->valueAt(row)); }); + } + static void castFromVarbinary( const BaseVector& input, exec::EvalCtx& context, diff --git a/velox/functions/prestosql/types/IPPrefixType.cpp b/velox/functions/prestosql/types/IPPrefixType.cpp index b835876df232..8963044f5a63 100644 --- a/velox/functions/prestosql/types/IPPrefixType.cpp +++ b/velox/functions/prestosql/types/IPPrefixType.cpp @@ -16,7 +16,6 @@ #include #include "velox/expression/CastExpr.h" -#include "velox/expression/VectorWriters.h" #include "velox/functions/prestosql/types/IPPrefixType.h" namespace facebook::velox { @@ -29,6 +28,8 @@ class IPPrefixCastOperator : public exec::CastOperator { switch (other->kind()) { case TypeKind::VARCHAR: return true; + case TypeKind::HUGEINT: + return isIPAddressType(other); default: return false; } @@ -38,6 +39,8 @@ class IPPrefixCastOperator : public exec::CastOperator { switch (other->kind()) { case TypeKind::VARCHAR: return true; + case TypeKind::HUGEINT: + return isIPAddressType(other); default: return false; } @@ -53,6 +56,12 @@ class IPPrefixCastOperator : public exec::CastOperator { switch (input.typeKind()) { case TypeKind::VARCHAR: return castFromString(input, context, rows, *result); + case TypeKind::HUGEINT: { + if (isIPAddressType(input.type())) { + return castFromIpAddress(input, context, rows, *result); + } + [[fallthrough]]; + } default: VELOX_NYI( "Cast from {} to IPPrefix not yet supported", @@ -85,7 +94,6 @@ class IPPrefixCastOperator : public exec::CastOperator { BaseVector& result) { auto* flatResult = result.as>(); auto rowVector = input.as(); - auto rowType = rowVector->type(); const auto* ipaddr = rowVector->childAt(ipaddress::kIpRowIndex) ->as>(); const auto* prefix = rowVector->childAt(ipaddress::kIpPrefixRowIndex) @@ -120,29 +128,55 @@ class IPPrefixCastOperator : public exec::CastOperator { }); } + static void castFromIpAddress( + const BaseVector& input, + exec::EvalCtx& context, + const SelectivityVector& rows, + BaseVector& result) { + auto* rowVectorResult = result.as(); + auto intIpAddrVec = + rowVectorResult->childAt(0)->asChecked>(); + auto intPrefixVec = + rowVectorResult->childAt(1)->asChecked>(); + DecodedVector decoded(input, rows); + + context.applyToSelectedNoThrow(rows, [&](auto row) { + auto intIpAddr = decoded.valueAt(row); + const auto tryPrefixLength = + ipaddress::tryIpPrefixLengthFromIPAddressType(intIpAddr); + if (FOLLY_UNLIKELY(tryPrefixLength.hasError())) { + context.setStatus(row, std::move(tryPrefixLength.error())); + return; + } + intIpAddrVec->set(row, intIpAddr); + intPrefixVec->set(row, tryPrefixLength.value()); + }); + } + static void castFromString( const BaseVector& input, exec::EvalCtx& context, const SelectivityVector& rows, BaseVector& result) { auto* rowVectorResult = result.as(); - const auto* ipPrefixStrings = input.as>(); + auto intIpAddrVec = + rowVectorResult->childAt(0)->asChecked>(); + auto intPrefixVec = + rowVectorResult->childAt(1)->asChecked>(); + + DecodedVector decoded(input, rows); context.applyToSelectedNoThrow(rows, [&](auto row) { - auto ipAddressStringView = ipPrefixStrings->valueAt(row); + auto ipAddressStringView = decoded.valueAt(row); auto tryIpPrefix = ipaddress::tryParseIpPrefixString(ipAddressStringView); if (tryIpPrefix.hasError()) { context.setStatus(row, std::move(tryIpPrefix.error())); + return; } const auto& ipPrefix = tryIpPrefix.value(); - auto writer = exec::VectorWriter>(); - writer.init(*rowVectorResult); - writer.setOffset(row); - auto& rowWriter = writer.current(); - rowWriter.get_writer_at<0>() = ipPrefix.first; - rowWriter.get_writer_at<1>() = ipPrefix.second; - writer.commit(); + intIpAddrVec->set(row, ipPrefix.first); + intPrefixVec->set(row, ipPrefix.second); }); } }; diff --git a/velox/functions/prestosql/types/IPPrefixType.h b/velox/functions/prestosql/types/IPPrefixType.h index 2bd95c2a132c..5ece386a4a3a 100644 --- a/velox/functions/prestosql/types/IPPrefixType.h +++ b/velox/functions/prestosql/types/IPPrefixType.h @@ -32,13 +32,22 @@ constexpr int kIPPrefixBytes = 17; constexpr auto kIpRowIndex = "ip"; constexpr auto kIpPrefixRowIndex = "prefix"; -namespace { -auto splitIpSlashCidr(folly::StringPiece ipSlashCidr) { - folly::small_vector vec; - folly::split('/', ipSlashCidr, vec); - return vec; +inline folly::Expected tryIpPrefixLengthFromIPAddressType( + const int128_t& intIpAddr) { + folly::ByteArray16 addrBytes = {0}; + memcpy(&addrBytes, &intIpAddr, sizeof(intIpAddr)); + std::reverse(addrBytes.begin(), addrBytes.end()); + auto tryV6Addr = folly::IPAddressV6::tryFromBinary(addrBytes); + if (tryV6Addr.hasError()) { + return folly::makeUnexpected( + threadSkipErrorDetails() + ? Status::UserError() + : Status::UserError("Received invalid ip address")); + } + + return tryV6Addr.value().isIPv4Mapped() ? ipaddress::kIPV4Bits + : ipaddress::kIPV6Bits; } -} // namespace inline folly::Expected, Status> tryParseIpPrefixString(folly::StringPiece ipprefixString) {