Skip to content

Commit

Permalink
Add IPPREFIX
Browse files Browse the repository at this point in the history
  • Loading branch information
mohsaka committed Aug 29, 2024
1 parent be52988 commit 2298a16
Show file tree
Hide file tree
Showing 16 changed files with 854 additions and 13 deletions.
18 changes: 18 additions & 0 deletions velox/docs/develop/types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ JSON VARCHAR
TIMESTAMP WITH TIME ZONE BIGINT
UUID HUGEINT
IPADDRESS HUGEINT
IPPREFIX VARBINARY
======================== =====================

TIMESTAMP WITH TIME ZONE represents a time point in milliseconds precision
Expand All @@ -155,6 +156,23 @@ used in IPADDRESS/IPPREFIX related functions. This type can be used to
create IPPREFIX networks as well as to check IPADDRESS validity within
IPPREFIX networks.

IPPREFIX represents an IPV6 or IPV4 formatted IPV6 address along with a one byte
prefix length. Its physical type is VARBINARY but has a fixed length of 17 bytes.
The format that the address is stored in is defined as part of `(RFC 4291#section-2.5.5.2) <https://datatracker.ietf.org/doc/html/rfc4291.html#section-2.5.5.2>`_.
The prefix length is stored in the last byte of the VARBINARY array.
The IP address stored is the canonical(smallest) IP address in the
subnet range. This type can be used in IP subnet functions.

Example:

In this example the first 32 bits(*FFFF:FFFF*) represents the network prefix.
As a result the IPPREFIX object stores *FFFF:FFFF::* and the length 32 for both of these IPPREFIX objects.

::

IPPREFIX 'FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF/32' -- IPPREFIX 'FFFF:FFFF:0000:0000:0000:0000:0000:0000/32'
IPPREFIX 'FFFF:FFFF:4455:6677:8899:AABB:CCDD:EEFF/32' -- IPPREFIX 'FFFF:FFFF:0000:0000:0000:0000:0000:0000/32'

Spark Types
~~~~~~~~~~~~
The `data types <https://spark.apache.org/docs/latest/sql-ref-datatypes.html>`_ in Spark have some semantic differences compared to those in
Expand Down
125 changes: 124 additions & 1 deletion velox/docs/functions/presto/conversion.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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

* -
Expand All @@ -49,6 +49,7 @@ supported conversions to/from JSON are listed in :doc:`json`.
- interval day to second
- decimal
- ipaddress
- ipprefix
* - tinyint
- Y
- Y
Expand All @@ -65,6 +66,7 @@ supported conversions to/from JSON are listed in :doc:`json`.
-
- Y
-
-
* - smallint
- Y
- Y
Expand All @@ -81,6 +83,7 @@ supported conversions to/from JSON are listed in :doc:`json`.
-
- Y
-
-
* - integer
- Y
- Y
Expand All @@ -97,6 +100,7 @@ supported conversions to/from JSON are listed in :doc:`json`.
-
- Y
-
-
* - bigint
- Y
- Y
Expand All @@ -113,6 +117,7 @@ supported conversions to/from JSON are listed in :doc:`json`.
-
- Y
-
-
* - boolean
- Y
- Y
Expand All @@ -129,6 +134,7 @@ supported conversions to/from JSON are listed in :doc:`json`.
-
- Y
-
-
* - real
- Y
- Y
Expand All @@ -145,6 +151,7 @@ supported conversions to/from JSON are listed in :doc:`json`.
-
- Y
-
-
* - double
- Y
- Y
Expand All @@ -161,6 +168,7 @@ supported conversions to/from JSON are listed in :doc:`json`.
-
- Y
-
-
* - varchar
- Y
- Y
Expand All @@ -177,6 +185,7 @@ supported conversions to/from JSON are listed in :doc:`json`.
-
- Y
- Y
- Y
* - varbinary
-
-
Expand All @@ -193,6 +202,7 @@ supported conversions to/from JSON are listed in :doc:`json`.
-
-
- Y
-
* - timestamp
-
-
Expand All @@ -209,6 +219,7 @@ supported conversions to/from JSON are listed in :doc:`json`.
-
-
-
-
* - timestamp with time zone
-
-
Expand All @@ -225,6 +236,7 @@ supported conversions to/from JSON are listed in :doc:`json`.
-
-
-
-
* - date
-
-
Expand All @@ -241,6 +253,7 @@ supported conversions to/from JSON are listed in :doc:`json`.
-
-
-
-
* - interval day to second
-
-
Expand All @@ -257,6 +270,7 @@ supported conversions to/from JSON are listed in :doc:`json`.
-
-
-
-
* - decimal
- Y
- Y
Expand All @@ -273,6 +287,7 @@ supported conversions to/from JSON are listed in :doc:`json`.
-
- Y
-
-
* - ipaddress
-
-
Expand All @@ -288,7 +303,25 @@ supported conversions to/from JSON are listed in :doc:`json`.
-
-
-
- Y
- Y
* - ipprefix
-
-
-
-
-
-
-
- Y
-
-
-
-
-
-
- Y
- Y

Cast to Integral Types
----------------------
Expand Down Expand Up @@ -689,6 +722,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/<prefix-length>* 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 <https://datatracker.ietf.org/doc/html/rfc4291.html#section-2.2>`_
followed by */<prefix-length>*. `[RFC 4291#section-2.3] <https://datatracker.ietf.org/doc/html/rfc4291.html#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
-----------------

Expand Down Expand Up @@ -1036,6 +1096,8 @@ Invalid example
Cast to IPADDRESS
-----------------

.. _ipaddress-varchar:

From VARCHAR
^^^^^^^^^^^^

Expand Down Expand Up @@ -1128,6 +1190,67 @@ 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 *<ip_address>/<ip_prefix>* as defined in `(RFC 4291#section-2.3) <https://datatracker.ietf.org/doc/html/rfc4291.html#section-2.3>`_
The IPADDRESS portion of the IPPREFIX follows the same rules as casting
`IPADDRESS to VARCHAR <#ipaddress-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); -- Invalid IP address '2001:db8::1::1'
SELECT cast('2001:0db8:0000:0000:0000:ff00:0042:8329/129' as ipprefix); -- CIDR value '129' is > network bit count '128'
SELECT cast('2001:0db8:0000:0000:0000:ff00:0042:8329/-1' as ipprefix); -- Mask value '-1' not a valid mask
SELECT cast('255.2.3.4/33' as ipprefix); -- CIDR value '33' is > network bit count '32'
SELECT cast('::ffff:ffff:ffff/33' as ipprefix); -- CIDR value '33' is > network bit count '32'


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::/128'

Miscellaneous
-------------

Expand Down
2 changes: 2 additions & 0 deletions velox/expression/tests/CustomTypeTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ TEST_F(CustomTypeTest, getCustomTypeNames) {
"TIMESTAMP WITH TIME ZONE",
"UUID",
"IPADDRESS",
"IPPREFIX",
}),
names);

Expand All @@ -231,6 +232,7 @@ TEST_F(CustomTypeTest, getCustomTypeNames) {
"TIMESTAMP WITH TIME ZONE",
"UUID",
"IPADDRESS",
"IPPREFIX",
"FANCY_INT",
}),
names);
Expand Down
2 changes: 2 additions & 0 deletions velox/functions/prestosql/IPAddressFunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
#pragma once

#include "velox/functions/prestosql/types/IPAddressType.h"
#include "velox/functions/prestosql/types/IPPrefixType.h"

namespace facebook::velox::functions {

void registerIPAddressFunctions(const std::string& prefix) {
registerIPAddressType();
registerIPPrefixType();
}

} // namespace facebook::velox::functions
3 changes: 3 additions & 0 deletions velox/functions/prestosql/TypeOf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "velox/expression/VectorFunction.h"
#include "velox/functions/prestosql/types/HyperLogLogType.h"
#include "velox/functions/prestosql/types/IPAddressType.h"
#include "velox/functions/prestosql/types/IPPrefixType.h"
#include "velox/functions/prestosql/types/JsonType.h"
#include "velox/functions/prestosql/types/TimestampWithTimeZoneType.h"
#include "velox/functions/prestosql/types/UuidType.h"
Expand Down Expand Up @@ -78,6 +79,8 @@ std::string typeName(const TypePtr& type) {
case TypeKind::VARBINARY:
if (isHyperLogLogType(type)) {
return "HyperLogLog";
} else if (isIPPrefixType(type)) {
return "ipaddress";
}
return "varbinary";
case TypeKind::TIMESTAMP:
Expand Down
1 change: 1 addition & 0 deletions velox/functions/prestosql/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ add_executable(
HyperLogLogFunctionsTest.cpp
InPredicateTest.cpp
IPAddressCastTest.cpp
IPPrefixCastTest.cpp
JsonCastTest.cpp
JsonExtractScalarTest.cpp
JsonFunctionsTest.cpp
Expand Down
10 changes: 5 additions & 5 deletions velox/functions/prestosql/tests/IPAddressCastTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,28 @@ namespace {
class IPAddressCastTest : public functions::test::FunctionBaseTest {
protected:
std::optional<std::string> castToVarchar(
const std::optional<std::string> input) {
const std::optional<std::string>& input) {
auto result = evaluateOnce<std::string>(
"cast(cast(c0 as ipaddress) as varchar)", input);
"cast(cast(cast(c0 as ipaddress) as ipaddress) as varchar)", input);
return result;
}

std::optional<int128_t> castFromVarbinary(
const std::optional<std::string> input) {
const std::optional<std::string>& input) {
auto result =
evaluateOnce<int128_t>("cast(from_hex(c0) as ipaddress)", input);
return result;
}

std::optional<std::string> allCasts(const std::optional<std::string> input) {
std::optional<std::string> allCasts(const std::optional<std::string>& input) {
auto result = evaluateOnce<std::string>(
"cast(cast(cast(cast(c0 as ipaddress) as varbinary) as ipaddress) as varchar)",
input);
return result;
}
};

int128_t stringToInt128(std::string value) {
int128_t stringToInt128(const std::string& value) {
int128_t res = 0;
for (char c : value) {
res = res * 10 + c - '0';
Expand Down
Loading

0 comments on commit 2298a16

Please sign in to comment.