From b556b7c76e676314a59aa22030537194977102e2 Mon Sep 17 00:00:00 2001 From: Nikolai Kochetov Date: Thu, 14 May 2020 17:21:38 +0300 Subject: [PATCH] Fix notNullIn with NULL argument. --- src/Functions/ignoreExceptNull.cpp | 56 ---------- src/Functions/in.cpp | 102 ++++++++---------- .../registerFunctionsMiscellaneous.cpp | 2 - src/Interpreters/ActionsVisitor.cpp | 8 +- 4 files changed, 47 insertions(+), 121 deletions(-) delete mode 100644 src/Functions/ignoreExceptNull.cpp diff --git a/src/Functions/ignoreExceptNull.cpp b/src/Functions/ignoreExceptNull.cpp deleted file mode 100644 index ff009533e37..00000000000 --- a/src/Functions/ignoreExceptNull.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include -#include -#include - - -namespace DB -{ - -/** ignoreExceptNull(...) is a function that takes any arguments, and always returns 0 except Null. - */ - class FunctionIgnoreExceptNull : public IFunction - { - public: - static constexpr auto name = "ignoreExceptNull"; - static FunctionPtr create(const Context &) - { - return std::make_shared(); - } - - bool isVariadic() const override - { - return true; - } - size_t getNumberOfArguments() const override - { - return 0; - } - - String getName() const override - { - return name; - } - - DataTypePtr getReturnTypeImpl(const DataTypes & /*arguments*/) const override - { - return std::make_shared(); - } - - void executeImpl(Block & block, const ColumnNumbers &, size_t result, size_t input_rows_count) override - { - /// This function is mainly used in query analysis instead of "in" functions - /// in the case when only header is needed and set for in is not calculated. - /// Because of that function must return the same column type as "in" function, which is ColumnUInt8. - auto res = ColumnUInt8::create(input_rows_count, 0); - block.getByPosition(result).column = std::move(res); - } - }; - - - void registerFunctionIgnoreExceptNull(FunctionFactory & factory) - { - factory.registerFunction(); - } - -} diff --git a/src/Functions/in.cpp b/src/Functions/in.cpp index a89535c675a..55cae1afc6c 100644 --- a/src/Functions/in.cpp +++ b/src/Functions/in.cpp @@ -21,62 +21,34 @@ namespace ErrorCodes * notIn(x, set) - and NOT IN. */ -template +template struct FunctionInName; -template <> -struct FunctionInName -{ - static constexpr auto name = "in"; -}; +template <> struct FunctionInName { static constexpr auto name = "in"; }; +template <> struct FunctionInName { static constexpr auto name = "globalIn"; }; +template <> struct FunctionInName { static constexpr auto name = "notIn"; }; +template <> struct FunctionInName { static constexpr auto name = "globalNotIn"; }; +template <> struct FunctionInName { static constexpr auto name = "nullIn"; }; +template <> struct FunctionInName { static constexpr auto name = "globalNullIn"; }; +template <> struct FunctionInName { static constexpr auto name = "notNullIn"; }; +template <> struct FunctionInName { static constexpr auto name = "globalNotNullIn"; }; +template <> struct FunctionInName { static constexpr auto name = "inIgnoreSet"; }; +template <> struct FunctionInName { static constexpr auto name = "globalInIgnoreSet"; }; +template <> struct FunctionInName { static constexpr auto name = "notInIgnoreSet"; }; +template <> struct FunctionInName { static constexpr auto name = "globalNotInIgnoreSet"; }; +template <> struct FunctionInName { static constexpr auto name = "nullInIgnoreSet"; }; +template <> struct FunctionInName { static constexpr auto name = "globalNullInIgnoreSet"; }; +template <> struct FunctionInName { static constexpr auto name = "notNullInIgnoreSet"; }; +template <> struct FunctionInName { static constexpr auto name = "globalNotNullInIgnoreSet"; }; -template <> -struct FunctionInName -{ - static constexpr auto name = "globalIn"; -}; - -template <> -struct FunctionInName -{ - static constexpr auto name = "notIn"; -}; - -template <> -struct FunctionInName -{ - static constexpr auto name = "globalNotIn"; -}; - -template <> -struct FunctionInName -{ - static constexpr auto name = "nullIn"; -}; - -template <> -struct FunctionInName -{ - static constexpr auto name = "globalNullIn"; -}; - -template <> -struct FunctionInName -{ - static constexpr auto name = "notNullIn"; -}; - -template <> -struct FunctionInName -{ - static constexpr auto name = "globalNotNullIn"; -}; - -template +template class FunctionIn : public IFunction { public: - static constexpr auto name = FunctionInName::name; + /// ignore_set flag means that we don't use set from the second argument, just return zero column. + /// It is needed to perform type analysis without creation of set. + static constexpr auto name = FunctionInName::name; + static FunctionPtr create(const Context &) { return std::make_shared(); @@ -101,9 +73,13 @@ public: bool useDefaultImplementationForNulls() const override { return null_is_skipped; } - void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) override + void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, [[maybe_unused]] size_t input_rows_count) override { - /// NOTE: after updating this code, check that FunctionIgnoreExceptNull returns the same type of column. + if constexpr (ignore_set) + { + block.getByPosition(result).column = DataTypeUInt8().createColumnConst(input_rows_count, 0u); + return; + } /// Second argument must be ColumnSet. ColumnPtr column_set_ptr = block.getByPosition(arguments[1]).column; @@ -146,17 +122,23 @@ public: } }; +template +static void registerFunctionsInImpl(FunctionFactory & factory) +{ + factory.registerFunction>(); + factory.registerFunction>(); + factory.registerFunction>(); + factory.registerFunction>(); + factory.registerFunction>(); + factory.registerFunction>(); + factory.registerFunction>(); + factory.registerFunction>(); +} void registerFunctionsIn(FunctionFactory & factory) { - factory.registerFunction>(); - factory.registerFunction>(); - factory.registerFunction>(); - factory.registerFunction>(); - factory.registerFunction>(); - factory.registerFunction>(); - factory.registerFunction>(); - factory.registerFunction>(); + registerFunctionsInImpl(factory); + registerFunctionsInImpl(factory); } } diff --git a/src/Functions/registerFunctionsMiscellaneous.cpp b/src/Functions/registerFunctionsMiscellaneous.cpp index 221e14fcce1..b932d232834 100644 --- a/src/Functions/registerFunctionsMiscellaneous.cpp +++ b/src/Functions/registerFunctionsMiscellaneous.cpp @@ -29,7 +29,6 @@ void registerFunctionSleep(FunctionFactory &); void registerFunctionSleepEachRow(FunctionFactory &); void registerFunctionMaterialize(FunctionFactory &); void registerFunctionIgnore(FunctionFactory &); -void registerFunctionIgnoreExceptNull(FunctionFactory &); void registerFunctionIdentity(FunctionFactory &); void registerFunctionArrayJoin(FunctionFactory &); void registerFunctionReplicate(FunctionFactory &); @@ -88,7 +87,6 @@ void registerFunctionsMiscellaneous(FunctionFactory & factory) registerFunctionSleepEachRow(factory); registerFunctionMaterialize(factory); registerFunctionIgnore(factory); - registerFunctionIgnoreExceptNull(factory); registerFunctionIdentity(factory); registerFunctionArrayJoin(factory); registerFunctionReplicate(factory); diff --git a/src/Interpreters/ActionsVisitor.cpp b/src/Interpreters/ActionsVisitor.cpp index 4d032e552ca..81f19d0b3dc 100644 --- a/src/Interpreters/ActionsVisitor.cpp +++ b/src/Interpreters/ActionsVisitor.cpp @@ -381,11 +381,13 @@ void ActionsMatcher::visit(const ASTFunction & node, const ASTPtr & ast, Data & if (!data.only_consts) { /// We are in the part of the tree that we are not going to compute. You just need to define types. - /// Do not subquery and create sets. We treat "IN" as "ignoreExceptNull" function. + /// Do not subquery and create sets. We replace "in*" function to "in*IgnoreSet". + + auto argument_name = node.arguments->children.at(0)->getColumnName(); data.addAction(ExpressionAction::applyFunction( - FunctionFactory::instance().get("ignoreExceptNull", data.context), - { node.arguments->children.at(0)->getColumnName() }, + FunctionFactory::instance().get(node.name + "IgnoreSet", data.context), + { argument_name, argument_name }, column_name.get(ast))); } return;