From 4ed57ac566772fa0db450558b6bf1956a9728fd9 Mon Sep 17 00:00:00 2001 From: Andrey Mironov Date: Fri, 3 Apr 2015 16:30:00 +0300 Subject: [PATCH] dbms: add functions isFinite, isInfinite, isNan [#METR-METR-15731] --- .../DB/Functions/FunctionsMiscellaneous.h | 114 ++++++++++++++++++ dbms/src/Functions/FunctionsMiscellaneous.cpp | 4 + ..._number_classification_functions.reference | 30 +++++ .../00143_number_classification_functions.sql | 33 +++++ 4 files changed, 181 insertions(+) create mode 100644 dbms/tests/queries/0_stateless/00143_number_classification_functions.reference create mode 100644 dbms/tests/queries/0_stateless/00143_number_classification_functions.sql diff --git a/dbms/include/DB/Functions/FunctionsMiscellaneous.h b/dbms/include/DB/Functions/FunctionsMiscellaneous.h index 6898de9061..789116733f 100644 --- a/dbms/include/DB/Functions/FunctionsMiscellaneous.h +++ b/dbms/include/DB/Functions/FunctionsMiscellaneous.h @@ -22,6 +22,7 @@ #include #include #include +#include namespace DB @@ -770,4 +771,117 @@ private: } }; + +template +class FunctionNumericPredicate : public IFunction +{ +public: + static constexpr auto name = Impl::name; + static IFunction * create(const Context &) { return new FunctionNumericPredicate; } + + String getName() const override { return name; } + + DataTypePtr getReturnType(const DataTypes & arguments) const override + { + const auto args_size = arguments.size(); + if (args_size != 1) + throw Exception{ + "Number of arguments for function " + getName() + " doesn't match: passed " + + toString(args_size) + ", should be 1", + ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH + }; + + const auto arg = arguments.front().get(); + if (!typeid_cast(arg) && + !typeid_cast(arg) && + !typeid_cast(arg) && + !typeid_cast(arg) && + !typeid_cast(arg) && + !typeid_cast(arg) && + !typeid_cast(arg) && + !typeid_cast(arg) && + !typeid_cast(arg) && + !typeid_cast(arg)) + throw Exception{ + "Argument for function " + getName() + " must be numeric", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT + }; + + return new DataTypeUInt8; + } + + void execute(Block & block, const ColumnNumbers & arguments, const size_t result) override + { + const auto in = block.getByPosition(arguments.front()).column.get(); + + if (!execute(block, in, result) && + !execute(block, in, result) && + !execute(block, in, result) && + !execute(block, in, result) && + !execute(block, in, result) && + !execute(block, in, result) && + !execute(block, in, result) && + !execute(block, in, result) && + !execute(block, in, result) && + !execute(block, in, result)) + throw Exception{ + "Illegal column " + in->getName() + " of first argument of function " + getName(), + ErrorCodes::ILLEGAL_COLUMN + }; + } + + template + bool execute(Block & block, const IColumn * in_untyped, const size_t result) override + { + if (const auto in = typeid_cast *>(in_untyped)) + { + const auto size = in->size(); + + const auto out = new ColumnVector{size}; + block.getByPosition(result).column = out; + + const auto & in_data = in->getData(); + auto & out_data = out->getData(); + + for (const auto i : ext::range(0, size)) + out_data[i] = Impl::execute(in_data[i]); + + return true; + } + else if (const auto in = typeid_cast *>(in_untyped)) + { + block.getByPosition(result).column = new ColumnConstUInt8{ + in->size(), + Impl::execute(in->getData()) + }; + + return true; + } + + return false; + } +}; + +struct IsFiniteImpl +{ + static constexpr auto name = "isFinite"; + template static bool execute(const T t) { return std::isfinite(t); } +}; + +struct IsInfiniteImpl +{ + static constexpr auto name = "isInfinite"; + template static bool execute(const T t) { return std::isinf(t); } +}; + +struct IsNanImpl +{ + static constexpr auto name = "isNan"; + template static bool execute(const T t) { return std::isnan(t); } +}; + +using FunctionIsFinite = FunctionNumericPredicate; +using FunctionIsInfinite = FunctionNumericPredicate; +using FunctionIsNan = FunctionNumericPredicate; + } diff --git a/dbms/src/Functions/FunctionsMiscellaneous.cpp b/dbms/src/Functions/FunctionsMiscellaneous.cpp index 222ed78c25..5d2dc66917 100644 --- a/dbms/src/Functions/FunctionsMiscellaneous.cpp +++ b/dbms/src/Functions/FunctionsMiscellaneous.cpp @@ -333,6 +333,10 @@ void registerFunctionsMiscellaneous(FunctionFactory & factory) factory.registerFunction>(); factory.registerFunction>(); factory.registerFunction>(); + + factory.registerFunction(); + factory.registerFunction(); + factory.registerFunction(); } } diff --git a/dbms/tests/queries/0_stateless/00143_number_classification_functions.reference b/dbms/tests/queries/0_stateless/00143_number_classification_functions.reference new file mode 100644 index 0000000000..ac8f48bbb7 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00143_number_classification_functions.reference @@ -0,0 +1,30 @@ +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 diff --git a/dbms/tests/queries/0_stateless/00143_number_classification_functions.sql b/dbms/tests/queries/0_stateless/00143_number_classification_functions.sql new file mode 100644 index 0000000000..8f37d518f7 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00143_number_classification_functions.sql @@ -0,0 +1,33 @@ +select isFinite(0) = 1; +select isFinite(1) = 1; +select isFinite(materialize(0)) = 1; +select isFinite(materialize(1)) = 1; +select isFinite(1/0) = 0; +select isFinite(-1/0) = 0; +select isFinite(0/0) = 0; +select isFinite(inf) = 0; +select isFinite(-inf) = 0; +select isFinite(nan) = 0; + +select isInfinite(0) = 0; +select isInfinite(1) = 0; +select isInfinite(materialize(0)) = 0; +select isInfinite(materialize(1)) = 0; +select isInfinite(1/0) = 1; +select isInfinite(-1/0) = 1; +select isInfinite(0/0) = 0; +select isInfinite(inf) = 1; +select isInfinite(-inf) = 1; +select isInfinite(nan) = 0; + + +select isNan(0) = 0; +select isNan(1) = 0; +select isNan(materialize(0)) = 0; +select isNan(materialize(1)) = 0; +select isNan(1/0) = 0; +select isNan(-1/0) = 0; +select isNan(0/0) = 1; +select isNan(inf) = 0; +select isNan(-inf) = 0; +select isNan(nan) = 1; -- GitLab