From 121f7ae833a7212cbe35954d783268f6cf64bcae Mon Sep 17 00:00:00 2001 From: spongedc Date: Tue, 22 Dec 2020 16:06:33 +0800 Subject: [PATCH] Support builtin function isIPv4String && isIPv6String --- src/Functions/FunctionsCoding.cpp | 2 + src/Functions/FunctionsCoding.h | 93 +++++++++++++++++++ .../00725_ipv4_ipv6_domains.reference | 24 +++++ .../0_stateless/00725_ipv4_ipv6_domains.sql | 27 ++++++ 4 files changed, 146 insertions(+) diff --git a/src/Functions/FunctionsCoding.cpp b/src/Functions/FunctionsCoding.cpp index 97add9bf32a..c2c746aad9e 100644 --- a/src/Functions/FunctionsCoding.cpp +++ b/src/Functions/FunctionsCoding.cpp @@ -32,6 +32,8 @@ void registerFunctionsCoding(FunctionFactory & factory) factory.registerFunction(); factory.registerFunction(); factory.registerFunction(); + factory.registerFunction(); + factory.registerFunction(); } } diff --git a/src/Functions/FunctionsCoding.h b/src/Functions/FunctionsCoding.h index ac3262f5131..9e761ace6fb 100644 --- a/src/Functions/FunctionsCoding.h +++ b/src/Functions/FunctionsCoding.h @@ -1831,5 +1831,98 @@ public: } }; +class FunctionIsIPv4String : public FunctionIPv4StringToNum +{ +public: + static constexpr auto name = "isIPv4String"; + + static FunctionPtr create(const Context &) { return std::make_shared(); } + + String getName() const override { return name; } + + DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override + { + if (!isString(arguments[0])) + throw Exception("Illegal type " + arguments[0]->getName() + " of argument of function " + getName(), + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + return std::make_shared(); + } + + ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t /*input_rows_count*/) const override + { + const ColumnPtr & column = arguments[0].column; + if (const ColumnString * col = checkAndGetColumn(column.get())) + { + auto col_res = ColumnUInt8::create(); + + ColumnUInt8::Container & vec_res = col_res->getData(); + vec_res.resize(col->size()); + + const ColumnString::Chars & vec_src = col->getChars(); + const ColumnString::Offsets & offsets_src = col->getOffsets(); + size_t prev_offset = 0; + UInt32 result = 0; + + for (size_t i = 0; i < vec_res.size(); ++i) + { + vec_res[i] = DB::parseIPv4(reinterpret_cast(&vec_src[prev_offset]), reinterpret_cast(&result)); + prev_offset = offsets_src[i]; + } + return col_res; + } + else + throw Exception("Illegal column " + arguments[0].column->getName() + + " of argument of function " + getName(), + ErrorCodes::ILLEGAL_COLUMN); + } +}; + +class FunctionIsIPv6String : public FunctionIPv6StringToNum +{ +public: + static constexpr auto name = "isIPv6String"; + + static FunctionPtr create(const Context &) { return std::make_shared(); } + + String getName() const override { return name; } + + DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override + { + if (!isString(arguments[0])) + throw Exception("Illegal type " + arguments[0]->getName() + " of argument of function " + getName(), + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + + return std::make_shared(); + } + + ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t /*input_rows_count*/) const override + { + const ColumnPtr & column = arguments[0].column; + + if (const ColumnString * col = checkAndGetColumn(column.get())) + { + auto col_res = ColumnUInt8::create(); + + ColumnUInt8::Container & vec_res = col_res->getData(); + vec_res.resize(col->size()); + + const ColumnString::Chars & vec_src = col->getChars(); + const ColumnString::Offsets & offsets_src = col->getOffsets(); + size_t prev_offset = 0; + char v[IPV6_BINARY_LENGTH]; + + for (size_t i = 0; i < vec_res.size(); ++i) + { + vec_res[i] = DB::parseIPv6(reinterpret_cast(&vec_src[prev_offset]), reinterpret_cast(v)); + prev_offset = offsets_src[i]; + } + return col_res; + } + else + throw Exception("Illegal column " + arguments[0].column->getName() + + " of argument of function " + getName(), + ErrorCodes::ILLEGAL_COLUMN); + } +}; } diff --git a/tests/queries/0_stateless/00725_ipv4_ipv6_domains.reference b/tests/queries/0_stateless/00725_ipv4_ipv6_domains.reference index 28051d15f65..5060b5253fe 100644 --- a/tests/queries/0_stateless/00725_ipv4_ipv6_domains.reference +++ b/tests/queries/0_stateless/00725_ipv4_ipv6_domains.reference @@ -25,3 +25,27 @@ ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF > 127.0.0.1 2001:db8:ac10:fe01:feed:babe:cafe:f00d > 127.0.0.1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff = 127.0.0.1 ::ffff:127.0.0.1 +0.0.0.0 is ipv4 string: 1 +255.255.255.255 is ipv4 string: 1 +192.168.0.91 is ipv4 string: 1 +127.0.0.1 is ipv4 string: 1 +8.8.8.8 is ipv4 string: 1 +hello is ipv4 string: 0 +0:0:0:0:0:0:0:0 is ipv4 string: 0 +0000:0000:0000:0000:0000:FFFF:C1FC:110A is ipv4 string: 0 +FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF is ipv4 string: 0 +::ffff:127.0.0.1 is ipv4 string: 0 +::ffff:8.8.8.8 is ipv4 string: 0 +2001:0DB8:AC10:FE01:FEED:BABE:CAFE:F00D is ipv4 string: 0 +0.0.0.0 is ipv6 string: 0 +255.255.255.255 is ipv6 string: 0 +192.168.0.91 is ipv6 string: 0 +127.0.0.1 is ipv6 string: 0 +8.8.8.8 is ipv6 string: 0 +hello is ipv6 string: 0 +0:0:0:0:0:0:0:0 is ipv6 string: 1 +0000:0000:0000:0000:0000:FFFF:C1FC:110A is ipv6 string: 1 +FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF is ipv6 string: 1 +::ffff:127.0.0.1 is ipv6 string: 1 +::ffff:8.8.8.8 is ipv6 string: 1 +2001:0DB8:AC10:FE01:FEED:BABE:CAFE:F00D is ipv6 string: 1 diff --git a/tests/queries/0_stateless/00725_ipv4_ipv6_domains.sql b/tests/queries/0_stateless/00725_ipv4_ipv6_domains.sql index c40e3190ed8..099dc20762e 100644 --- a/tests/queries/0_stateless/00725_ipv4_ipv6_domains.sql +++ b/tests/queries/0_stateless/00725_ipv4_ipv6_domains.sql @@ -57,3 +57,30 @@ SELECT '= 127.0.0.1', ipv6_ FROM ipv6_test -- TODO: Assert that invalid values can't be inserted into IPv6 column. DROP TABLE IF EXISTS ipv6_test; + +SELECT '0.0.0.0 is ipv4 string: ', isIPv4String('0.0.0.0'); +SELECT '255.255.255.255 is ipv4 string: ', isIPv4String('255.255.255.255'); +SELECT '192.168.0.91 is ipv4 string: ', isIPv4String('192.168.0.91'); +SELECT '127.0.0.1 is ipv4 string: ', isIPv4String('127.0.0.1'); +SELECT '8.8.8.8 is ipv4 string: ', isIPv4String('8.8.8.8'); +SELECT 'hello is ipv4 string: ', isIPv4String('hello'); +SELECT '0:0:0:0:0:0:0:0 is ipv4 string: ', isIPv4String('0:0:0:0:0:0:0:0'); +SELECT '0000:0000:0000:0000:0000:FFFF:C1FC:110A is ipv4 string: ', isIPv4String('0000:0000:0000:0000:0000:FFFF:C1FC:110A'); +SELECT 'FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF is ipv4 string: ', isIPv4String('FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF'); +SELECT '::ffff:127.0.0.1 is ipv4 string: ', isIPv4String('::ffff:127.0.0.1'); +SELECT '::ffff:8.8.8.8 is ipv4 string: ', isIPv4String('::ffff:8.8.8.8'); +SELECT '2001:0DB8:AC10:FE01:FEED:BABE:CAFE:F00D is ipv4 string: ', isIPv4String('2001:0DB8:AC10:FE01:FEED:BABE:CAFE:F00D'); + +SELECT '0.0.0.0 is ipv6 string: ', isIPv6String('0.0.0.0'); +SELECT '255.255.255.255 is ipv6 string: ', isIPv6String('255.255.255.255'); +SELECT '192.168.0.91 is ipv6 string: ', isIPv6String('192.168.0.91'); +SELECT '127.0.0.1 is ipv6 string: ', isIPv6String('127.0.0.1'); +SELECT '8.8.8.8 is ipv6 string: ', isIPv6String('8.8.8.8'); +SELECT 'hello is ipv6 string: ', isIPv6String('hello'); +SELECT '0:0:0:0:0:0:0:0 is ipv6 string: ', isIPv6String('0:0:0:0:0:0:0:0'); +SELECT '0000:0000:0000:0000:0000:FFFF:C1FC:110A is ipv6 string: ', isIPv6String('0000:0000:0000:0000:0000:FFFF:C1FC:110A'); +SELECT 'FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF is ipv6 string: ', isIPv6String('FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF'); +SELECT '::ffff:127.0.0.1 is ipv6 string: ', isIPv6String('::ffff:127.0.0.1'); +SELECT '::ffff:8.8.8.8 is ipv6 string: ', isIPv6String('::ffff:8.8.8.8'); +SELECT '2001:0DB8:AC10:FE01:FEED:BABE:CAFE:F00D is ipv6 string: ', isIPv6String('2001:0DB8:AC10:FE01:FEED:BABE:CAFE:F00D'); +