From 45613f1d14841756a15219c7ecb81aadd59496b9 Mon Sep 17 00:00:00 2001 From: Robert Schulze Date: Wed, 3 Jan 2024 09:18:25 +0000 Subject: [PATCH] Refactor punycodeEncode/Decode() functions to inerit from IFunction directly --- src/Functions/punycode.cpp | 123 +++++++++++++++---- tests/queries/0_stateless/02932_punycode.sql | 4 +- 2 files changed, 101 insertions(+), 26 deletions(-) diff --git a/src/Functions/punycode.cpp b/src/Functions/punycode.cpp index c11409f0d1a..fb89759b24d 100644 --- a/src/Functions/punycode.cpp +++ b/src/Functions/punycode.cpp @@ -2,8 +2,11 @@ #if USE_IDNA +#include +#include #include -#include +#include +#include #ifdef __clang__ # pragma clang diagnostic push @@ -24,8 +27,57 @@ namespace ErrorCodes extern const int ILLEGAL_COLUMN; } -struct PunycodeEncodeImpl +namespace { + +enum class ExceptionMode +{ + Throw, + Null +}; + +template +class FunctionPunycodeEncode : public IFunction +{ +public: + static constexpr auto name = (exception_mode == ExceptionMode::Null) ? "punycodeEncodeOrNull" : "punycodeEncode"; + + static FunctionPtr create(ContextPtr) { return std::make_shared(); } + String getName() const override { return name; } + size_t getNumberOfArguments() const override { return 1; } + bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } + bool useDefaultImplementationForConstants() const override { return true; } + + DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override + { + FunctionArgumentDescriptors args{ + {"str", &isString, nullptr, "String"}, + }; + validateFunctionArgumentTypes(*this, arguments, args); + + auto return_type = std::make_shared(); + + if constexpr (exception_mode == ExceptionMode::Null) + return makeNullable(return_type); + else + return return_type; + } + + 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 = ColumnString::create(); + vector(col->getChars(), col->getOffsets(), col_res->getChars(), col_res->getOffsets()); + return col_res; + } + else + throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of argument of function {}", + arguments[0].column->getName(), getName()); + } + +private: static void vector( const ColumnString::Chars & data, const ColumnString::Offsets & offsets, @@ -61,15 +113,50 @@ struct PunycodeEncodeImpl value_puny.clear(); /// utf32_to_punycode() appends to its output string } } - - [[noreturn]] static void vectorFixed(const ColumnString::Chars &, size_t, ColumnString::Chars &) - { - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Column of type FixedString is not supported by punycodeEncode function"); - } }; -struct PunycodeDecodeImpl +template +class FunctionPunycodeDecode : public IFunction { +public: + static constexpr auto name = (exception_mode == ExceptionMode::Null) ? "punycodeDecodeOrNull" : "punycodeDecode"; + + static FunctionPtr create(ContextPtr) { return std::make_shared(); } + String getName() const override { return name; } + size_t getNumberOfArguments() const override { return 1; } + bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; } + bool useDefaultImplementationForConstants() const override { return true; } + + DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override + { + FunctionArgumentDescriptors args{ + {"str", &isString, nullptr, "String"}, + }; + validateFunctionArgumentTypes(*this, arguments, args); + + auto return_type = std::make_shared(); + + if constexpr (exception_mode == ExceptionMode::Null) + return makeNullable(return_type); + else + return return_type; + } + + 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 = ColumnString::create(); + vector(col->getChars(), col->getOffsets(), col_res->getChars(), col_res->getOffsets()); + return col_res; + } + else + throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of argument of function {}", + arguments[0].column->getName(), getName()); + } + +private: static void vector( const ColumnString::Chars & data, const ColumnString::Offsets & offsets, @@ -106,26 +193,13 @@ struct PunycodeDecodeImpl value_utf8.clear(); } } - - [[noreturn]] static void vectorFixed(const ColumnString::Chars &, size_t, ColumnString::Chars &) - { - throw Exception(ErrorCodes::ILLEGAL_COLUMN, "Column of type FixedString is not supported by punycodeDecode function"); - } }; -struct NamePunycodeEncode -{ - static constexpr auto name = "punycodeEncode"; -}; - -struct NamePunycodeDecode -{ - static constexpr auto name = "punycodeDecode"; -}; +} REGISTER_FUNCTION(Punycode) { - factory.registerFunction>(FunctionDocumentation{ + factory.registerFunction>(FunctionDocumentation{ .description=R"( Computes a Punycode representation of a string.)", .syntax="punycodeEncode(str)", @@ -142,7 +216,7 @@ Computes a Punycode representation of a string.)", }} }); - factory.registerFunction>(FunctionDocumentation{ + factory.registerFunction>(FunctionDocumentation{ .description=R"( Computes a Punycode representation of a string.)", .syntax="punycodeDecode(str)", @@ -158,6 +232,7 @@ Computes a Punycode representation of a string.)", )" }} }); + } } diff --git a/tests/queries/0_stateless/02932_punycode.sql b/tests/queries/0_stateless/02932_punycode.sql index dd18a43ecc9..afc3c7e8712 100644 --- a/tests/queries/0_stateless/02932_punycode.sql +++ b/tests/queries/0_stateless/02932_punycode.sql @@ -9,8 +9,8 @@ SELECT punycodeDecode(1); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT } SELECT punycodeEncode(1); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT } SELECT punycodeDecode('two', 'strings'); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH } SELECT punycodeEncode('two', 'strings'); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH } -SELECT punycodeDecode(toFixedString('two', 3)); -- { serverError ILLEGAL_COLUMN } -SELECT punycodeEncode(toFixedString('two', 3)); -- { serverError ILLEGAL_COLUMN } +SELECT punycodeDecode(toFixedString('two', 3)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT } +SELECT punycodeEncode(toFixedString('two', 3)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT } SELECT '-- Regular cases';