From ce70e4f238f04ed28d7ac743bfb0576668ece6e4 Mon Sep 17 00:00:00 2001 From: Vasily Nemkov Date: Sun, 19 May 2019 22:22:51 +0300 Subject: [PATCH 1/4] IN function result Allowing function result to be used on the right side of IN statement. All functions except aggregate ones, should work just Ok. Fixed printing AST of operator IN. --- dbms/src/Interpreters/ActionsVisitor.cpp | 104 +++++++++++------- dbms/src/Parsers/ASTFunction.cpp | 6 +- dbms/src/Parsers/ASTLiteral.h | 1 + ...function_result_with_operator_in.reference | 7 ++ ...00936_function_result_with_operator_in.sql | 34 ++++++ ...48_format_in_with_single_element.reference | 10 +- 6 files changed, 116 insertions(+), 46 deletions(-) create mode 100644 dbms/tests/queries/0_stateless/00936_function_result_with_operator_in.reference create mode 100644 dbms/tests/queries/0_stateless/00936_function_result_with_operator_in.sql diff --git a/dbms/src/Interpreters/ActionsVisitor.cpp b/dbms/src/Interpreters/ActionsVisitor.cpp index d0237f7cb88..86da996e153 100644 --- a/dbms/src/Interpreters/ActionsVisitor.cpp +++ b/dbms/src/Interpreters/ActionsVisitor.cpp @@ -82,21 +82,7 @@ SetPtr makeExplicitSet( if (prepared_sets.count(set_key)) return prepared_sets.at(set_key); /// Already prepared. - auto getTupleTypeFromAst = [&context](const ASTPtr & tuple_ast) -> DataTypePtr - { - const auto * func = tuple_ast->as(); - if (func && func->name == "tuple" && !func->arguments->children.empty()) - { - /// Won't parse all values of outer tuple. - auto element = func->arguments->children.at(0); - std::pair value_raw = evaluateConstantExpression(element, context); - return std::make_shared(DataTypes({value_raw.second})); - } - - return evaluateConstantExpression(tuple_ast, context).second; - }; - - const DataTypePtr & right_arg_type = getTupleTypeFromAst(right_arg); + const auto right_arg_evaluated = evaluateConstantExpression(right_arg, context); std::function getTupleDepth; getTupleDepth = [&getTupleDepth](const DataTypePtr & type) -> size_t @@ -107,37 +93,77 @@ SetPtr makeExplicitSet( return 0; }; - size_t left_tuple_depth = getTupleDepth(left_arg_type); - size_t right_tuple_depth = getTupleDepth(right_arg_type); + const auto& right_arg_type = right_arg_evaluated.second; + const auto& right_arg_value = right_arg_evaluated.first; - ASTPtr elements_ast = nullptr; - - /// 1 in 1; (1, 2) in (1, 2); identity(tuple(tuple(tuple(1)))) in tuple(tuple(tuple(1))); etc. - if (left_tuple_depth == right_tuple_depth) + const size_t left_tuple_depth = getTupleDepth(left_arg_type); + const size_t right_tuple_depth = getTupleDepth(right_arg_type); + if (left_tuple_depth != right_tuple_depth && left_tuple_depth + 1 != right_tuple_depth) { - ASTPtr exp_list = std::make_shared(); - exp_list->children.push_back(right_arg); - elements_ast = exp_list; - } - /// 1 in (1, 2); (1, 2) in ((1, 2), (3, 4)); etc. - else if (left_tuple_depth + 1 == right_tuple_depth) - { - const auto * set_func = right_arg->as(); - - if (!set_func || set_func->name != "tuple") - throw Exception("Incorrect type of 2nd argument for function " + node->name - + ". Must be subquery or set of elements with type " + left_arg_type->getName() + ".", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); - - elements_ast = set_func->arguments; - } - else throw Exception("Invalid types for IN function: " + left_arg_type->getName() + " and " + right_arg_type->getName() + ".", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + } + + Block block; + auto col = left_arg_type->createColumn(); + switch (right_arg_type->getTypeId()) + { + case TypeIndex::UInt8: [[fallthrough]]; + case TypeIndex::UInt16: [[fallthrough]]; + case TypeIndex::UInt32: [[fallthrough]]; + case TypeIndex::UInt64: [[fallthrough]]; + case TypeIndex::UInt128: [[fallthrough]]; + case TypeIndex::Int8: [[fallthrough]]; + case TypeIndex::Int16: [[fallthrough]]; + case TypeIndex::Int32: [[fallthrough]]; + case TypeIndex::Int64: [[fallthrough]]; + case TypeIndex::Int128: [[fallthrough]]; + case TypeIndex::Float32: [[fallthrough]]; + case TypeIndex::Float64: [[fallthrough]]; + case TypeIndex::Date: [[fallthrough]]; + case TypeIndex::DateTime: [[fallthrough]]; + case TypeIndex::String: [[fallthrough]]; + case TypeIndex::FixedString: [[fallthrough]]; + case TypeIndex::Enum8: [[fallthrough]]; + case TypeIndex::Enum16: [[fallthrough]]; + case TypeIndex::Decimal32: [[fallthrough]]; + case TypeIndex::Decimal64: [[fallthrough]]; + case TypeIndex::Decimal128: [[fallthrough]]; + case TypeIndex::UUID: + { + col->insert(convertFieldToType(right_arg_value, *left_arg_type, right_arg_type.get())); + break; + } + // flatten compound values: + case TypeIndex::Array: [[fallthrough]]; + case TypeIndex::Tuple: [[fallthrough]]; + case TypeIndex::Set: + { + const Array & array = DB::get(right_arg_value); + if (array.size() == 0) + break; + + for (size_t i = 0 ; i < array.size(); ++i) + { + col->insert(convertFieldToType(array[i], *left_arg_type, nullptr)); + } + break; + } + default: + throw Exception("Unsupported value type at the right-side of IN:" + + right_arg_type->getName() + ".", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + } + block.insert(ColumnWithTypeAndName{std::move(col), + left_arg_type, + "dummy_" + left_arg_type->getName()}); SetPtr set = std::make_shared(size_limits, create_ordered_set); - set->createFromAST(set_element_types, elements_ast, context); + + set->setHeader(block); + set->insertFromBlock(block); + prepared_sets[set_key] = set; return set; } diff --git a/dbms/src/Parsers/ASTFunction.cpp b/dbms/src/Parsers/ASTFunction.cpp index 5c5dbc9ba90..00ac8506b7f 100644 --- a/dbms/src/Parsers/ASTFunction.cpp +++ b/dbms/src/Parsers/ASTFunction.cpp @@ -187,8 +187,10 @@ void ASTFunction::formatImplWithoutAlias(const FormatSettings & settings, Format const auto * second_arg_func = arguments->children[1]->as(); const auto * second_arg_literal = arguments->children[1]->as(); bool extra_parents_around_in_rhs = (name == "in" || name == "notIn" || name == "globalIn" || name == "globalNotIn") - && !(second_arg_func && second_arg_func->name == "tuple") - && !(second_arg_literal && second_arg_literal->value.getType() == Field::Types::Tuple) + && !second_arg_func + && !(second_arg_literal + && (second_arg_literal->value.getType() == Field::Types::Tuple + || second_arg_literal->value.getType() == Field::Types::Array)) && !arguments->children[1]->as(); if (extra_parents_around_in_rhs) diff --git a/dbms/src/Parsers/ASTLiteral.h b/dbms/src/Parsers/ASTLiteral.h index dd5bb572e7d..628ed333ed3 100644 --- a/dbms/src/Parsers/ASTLiteral.h +++ b/dbms/src/Parsers/ASTLiteral.h @@ -15,6 +15,7 @@ class ASTLiteral : public ASTWithAlias public: Field value; + ASTLiteral(Field && value_) : value(value_) {} ASTLiteral(const Field & value_) : value(value_) {} /** Get the text that identifies this element. */ diff --git a/dbms/tests/queries/0_stateless/00936_function_result_with_operator_in.reference b/dbms/tests/queries/0_stateless/00936_function_result_with_operator_in.reference new file mode 100644 index 00000000000..7c650247cf4 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00936_function_result_with_operator_in.reference @@ -0,0 +1,7 @@ +5 +2 +5 +empty: +0 +0 +errors: diff --git a/dbms/tests/queries/0_stateless/00936_function_result_with_operator_in.sql b/dbms/tests/queries/0_stateless/00936_function_result_with_operator_in.sql new file mode 100644 index 00000000000..fe0f0bc3a1f --- /dev/null +++ b/dbms/tests/queries/0_stateless/00936_function_result_with_operator_in.sql @@ -0,0 +1,34 @@ +SET force_primary_key = 1; + +DROP TABLE IF EXISTS samples; +CREATE TABLE samples (key UInt32, value UInt32) ENGINE = MergeTree() ORDER BY key PRIMARY KEY key; +INSERT INTO samples VALUES (1, 1)(2, 2)(3, 3)(4, 4)(5, 5); + +-- all etries, verify that index is used +SELECT count() FROM samples WHERE key IN range(10); + +-- some entries: +SELECT count() FROM samples WHERE key IN arraySlice(range(100), 5, 10); + +-- different type +SELECT count() FROM samples WHERE toUInt64(key) IN range(100); + +SELECT 'empty:'; +-- should be empty +SELECT count() FROM samples WHERE key IN arraySlice(range(100), 10, 10); + +-- not only ints: +SELECT 'a' IN splitByChar('c', 'abcdef'); + +SELECT 'errors:'; +-- non-constant expressions in the right side of IN +SELECT count() FROM samples WHERE 1 IN range(samples.value); -- { serverError 47 } +SELECT count() FROM samples WHERE 1 IN range(rand()); -- { serverError 36 } + +-- index is not used +SELECT count() FROM samples WHERE value IN range(3); -- { serverError 277 } + +-- wrong type +SELECT 123 IN splitByChar('c', 'abcdef'); -- { serverError 53 } + +DROP TABLE samples; \ No newline at end of file diff --git a/dbms/tests/queries/0_stateless/00948_format_in_with_single_element.reference b/dbms/tests/queries/0_stateless/00948_format_in_with_single_element.reference index 91f53ffadb0..e843bb2b350 100644 --- a/dbms/tests/queries/0_stateless/00948_format_in_with_single_element.reference +++ b/dbms/tests/queries/0_stateless/00948_format_in_with_single_element.reference @@ -1,13 +1,13 @@ SELECT 1 IN (1) SELECT 1 IN (1) SELECT 1 IN (1, 2) -SELECT 1 IN (f(1)) -SELECT 1 IN (f(1)) +SELECT 1 IN f(1) +SELECT 1 IN f(1) SELECT 1 IN (f(1), f(2)) -SELECT 1 IN (f(1, 2)) +SELECT 1 IN f(1, 2) SELECT 1 IN (1 + 1) SELECT 1 IN ('hello') -SELECT 1 IN (f('hello')) +SELECT 1 IN f('hello') SELECT 1 IN ('hello', 'world') -SELECT 1 IN (f('hello', 'world')) +SELECT 1 IN f('hello', 'world') SELECT 1 IN (SELECT 1) From d8331d9dcb96e120735d8f76dd2292b853ebb112 Mon Sep 17 00:00:00 2001 From: CurtizJ Date: Fri, 24 Jan 2020 03:33:38 +0300 Subject: [PATCH 2/4] fix in operator with constant arrays --- dbms/src/Interpreters/ActionsVisitor.cpp | 145 ++++++++++-------- dbms/src/Interpreters/Set.cpp | 1 - dbms/src/Interpreters/Set.h | 1 - ...00936_function_result_with_operator_in.sql | 2 +- .../0_stateless/01071_in_array.reference | 8 + .../queries/0_stateless/01071_in_array.sql | 8 + 6 files changed, 98 insertions(+), 67 deletions(-) create mode 100644 dbms/tests/queries/0_stateless/01071_in_array.reference create mode 100644 dbms/tests/queries/0_stateless/01071_in_array.sql diff --git a/dbms/src/Interpreters/ActionsVisitor.cpp b/dbms/src/Interpreters/ActionsVisitor.cpp index 39f2a2bb790..b359ef101f0 100644 --- a/dbms/src/Interpreters/ActionsVisitor.cpp +++ b/dbms/src/Interpreters/ActionsVisitor.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -11,6 +12,7 @@ #include #include #include +#include #include #include @@ -50,6 +52,7 @@ namespace ErrorCodes extern const int UNEXPECTED_EXPRESSION; extern const int TYPE_MISMATCH; extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; + extern const int INCORRECT_ELEMENT_OF_SET; } static NamesAndTypesList::iterator findColumn(const String & name, NamesAndTypesList & cols) @@ -58,6 +61,58 @@ static NamesAndTypesList::iterator findColumn(const String & name, NamesAndTypes [&](const NamesAndTypesList::value_type & val) { return val.name == name; }); } +static Block createBlockFromArray(const Array & array, const DataTypes & types) +{ + size_t columns_num = types.size(); + MutableColumns columns(columns_num); + for (size_t i = 0; i < columns_num; ++i) + columns[i] = types[i]->createColumn(); + + Row tuple_values; + for (const auto & value : array) + { + if (columns_num == 1) + { + auto field = convertFieldToType(value, *types[0]); + if (!field.isNull()) + columns[0]->insert(std::move(field)); + } + else + { + if (value.getType() != Field::Types::Tuple) + throw Exception("Invalid type in set. Expected tuple, got " + + String(value.getTypeName()), ErrorCodes::INCORRECT_ELEMENT_OF_SET); + + const auto & tuple = DB::get(value); + size_t tuple_size = tuple.size(); + + if (tuple_size != columns_num) + throw Exception("Incorrect size of tuple in set: " + toString(tuple_size) + + " instead of " + toString(columns_num), ErrorCodes::INCORRECT_ELEMENT_OF_SET); + + if (tuple_values.empty()) + tuple_values.resize(tuple_size); + + size_t i = 0; + for (; i < tuple_size; ++i) + { + tuple_values[i] = convertFieldToType(tuple[i], *types[i]); + if (tuple_values[i].isNull()) + break; + } + + if (i == tuple_size) + for (i = 0; i < tuple_size; ++i) + columns[i]->insert(std::move(tuple_values[i])); + } + } + + Block res; + for (size_t i = 0; i < columns_num; ++i) + res.insert(ColumnWithTypeAndName{std::move(columns[i]), types[i], "_" + toString(i)}); + return res; +} + SetPtr makeExplicitSet( const ASTFunction * node, const Block & sample_block, bool create_ordered_set, const Context & context, const SizeLimits & size_limits, PreparedSets & prepared_sets) @@ -87,80 +142,42 @@ SetPtr makeExplicitSet( const auto right_arg_evaluated = evaluateConstantExpression(right_arg, context); - std::function getTupleDepth; - getTupleDepth = [&getTupleDepth](const DataTypePtr & type) -> size_t + std::function getTypeDepth; + getTypeDepth = [&getTypeDepth](const DataTypePtr & type) -> size_t { - if (auto tuple_type = typeid_cast(type.get())) - return 1 + (tuple_type->getElements().empty() ? 0 : getTupleDepth(tuple_type->getElements().at(0))); + if (auto array_type = typeid_cast(type.get())) + return 1 + getTypeDepth(array_type->getNestedType()); + else if (auto tuple_type = typeid_cast(type.get())) + return 1 + (tuple_type->getElements().empty() ? 0 : getTypeDepth(tuple_type->getElements().at(0))); return 0; }; - const auto& right_arg_type = right_arg_evaluated.second; - const auto& right_arg_value = right_arg_evaluated.first; + const auto & right_arg_type = right_arg_evaluated.second; + const auto & right_arg_value = right_arg_evaluated.first; - const size_t left_tuple_depth = getTupleDepth(left_arg_type); - const size_t right_tuple_depth = getTupleDepth(right_arg_type); - if (left_tuple_depth != right_tuple_depth && left_tuple_depth + 1 != right_tuple_depth) - { - throw Exception("Invalid types for IN function: " - + left_arg_type->getName() + " and " + right_arg_type->getName() + ".", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); - } + const size_t left_type_depth = getTypeDepth(left_arg_type); + const size_t right_type_depth = getTypeDepth(right_arg_type); Block block; - auto col = left_arg_type->createColumn(); - switch (right_arg_type->getTypeId()) + /// 1 in 1; (1, 2) in (1, 2); identity(tuple(tuple(tuple(1)))) in tuple(tuple(tuple(1))); etc. + if (left_type_depth == right_type_depth) { - case TypeIndex::UInt8: [[fallthrough]]; - case TypeIndex::UInt16: [[fallthrough]]; - case TypeIndex::UInt32: [[fallthrough]]; - case TypeIndex::UInt64: [[fallthrough]]; - case TypeIndex::UInt128: [[fallthrough]]; - case TypeIndex::Int8: [[fallthrough]]; - case TypeIndex::Int16: [[fallthrough]]; - case TypeIndex::Int32: [[fallthrough]]; - case TypeIndex::Int64: [[fallthrough]]; - case TypeIndex::Int128: [[fallthrough]]; - case TypeIndex::Float32: [[fallthrough]]; - case TypeIndex::Float64: [[fallthrough]]; - case TypeIndex::Date: [[fallthrough]]; - case TypeIndex::DateTime: [[fallthrough]]; - case TypeIndex::String: [[fallthrough]]; - case TypeIndex::FixedString: [[fallthrough]]; - case TypeIndex::Enum8: [[fallthrough]]; - case TypeIndex::Enum16: [[fallthrough]]; - case TypeIndex::Decimal32: [[fallthrough]]; - case TypeIndex::Decimal64: [[fallthrough]]; - case TypeIndex::Decimal128: [[fallthrough]]; - case TypeIndex::UUID: - { - col->insert(convertFieldToType(right_arg_value, *left_arg_type, right_arg_type.get())); - break; - } - // flatten compound values: - case TypeIndex::Array: [[fallthrough]]; - case TypeIndex::Tuple: [[fallthrough]]; - case TypeIndex::Set: - { - const Array & array = DB::get(right_arg_value); - if (array.size() == 0) - break; - - for (size_t i = 0 ; i < array.size(); ++i) - { - col->insert(convertFieldToType(array[i], *left_arg_type, nullptr)); - } - break; - } - default: - throw Exception("Unsupported value type at the right-side of IN:" - + right_arg_type->getName() + ".", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + Array array{right_arg_value}; + block = createBlockFromArray(array, set_element_types); + } + /// 1 in (1, 2); (1, 2) in ((1, 2), (3, 4)); etc. + else if (left_type_depth + 1 == right_type_depth) + { + const Array & array = DB::safeGet(right_arg_value); + block = createBlockFromArray(array, set_element_types); + } + else + { + throw Exception("Unsupported value type at the right-side of IN:" + + right_arg_type->getName() + ".", + ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); } - block.insert(ColumnWithTypeAndName{std::move(col), - left_arg_type, - "dummy_" + left_arg_type->getName()}); SetPtr set = std::make_shared(size_limits, create_ordered_set); diff --git a/dbms/src/Interpreters/Set.cpp b/dbms/src/Interpreters/Set.cpp index 2a6c8bf9656..4bd77621312 100644 --- a/dbms/src/Interpreters/Set.cpp +++ b/dbms/src/Interpreters/Set.cpp @@ -228,7 +228,6 @@ static Field extractValueFromNode(const ASTPtr & node, const IDataType & type, c throw Exception("Incorrect element of set. Must be literal or constant expression.", ErrorCodes::INCORRECT_ELEMENT_OF_SET); } - void Set::createFromAST(const DataTypes & types, ASTPtr node, const Context & context) { /// Will form a block with values from the set. diff --git a/dbms/src/Interpreters/Set.h b/dbms/src/Interpreters/Set.h index 1f19bdaa2cb..d0dcbb5ceeb 100644 --- a/dbms/src/Interpreters/Set.h +++ b/dbms/src/Interpreters/Set.h @@ -45,7 +45,6 @@ public: /** Create a Set from expression (specified literally in the query). * 'types' - types of what are on the left hand side of IN. * 'node' - list of values: 1, 2, 3 or list of tuples: (1, 2), (3, 4), (5, 6). - * 'fill_set_elements' - if true, fill vector of elements. For primary key to work. */ void createFromAST(const DataTypes & types, ASTPtr node, const Context & context); diff --git a/dbms/tests/queries/0_stateless/00936_function_result_with_operator_in.sql b/dbms/tests/queries/0_stateless/00936_function_result_with_operator_in.sql index fe0f0bc3a1f..dfb19c1f3ec 100644 --- a/dbms/tests/queries/0_stateless/00936_function_result_with_operator_in.sql +++ b/dbms/tests/queries/0_stateless/00936_function_result_with_operator_in.sql @@ -23,7 +23,7 @@ SELECT 'a' IN splitByChar('c', 'abcdef'); SELECT 'errors:'; -- non-constant expressions in the right side of IN SELECT count() FROM samples WHERE 1 IN range(samples.value); -- { serverError 47 } -SELECT count() FROM samples WHERE 1 IN range(rand()); -- { serverError 36 } +SELECT count() FROM samples WHERE 1 IN range(rand() % 1000); -- { serverError 36 } -- index is not used SELECT count() FROM samples WHERE value IN range(3); -- { serverError 277 } diff --git a/dbms/tests/queries/0_stateless/01071_in_array.reference b/dbms/tests/queries/0_stateless/01071_in_array.reference new file mode 100644 index 00000000000..a561412c1f2 --- /dev/null +++ b/dbms/tests/queries/0_stateless/01071_in_array.reference @@ -0,0 +1,8 @@ +1 +1 +1 +1 +\N +0 +1 +1 diff --git a/dbms/tests/queries/0_stateless/01071_in_array.sql b/dbms/tests/queries/0_stateless/01071_in_array.sql new file mode 100644 index 00000000000..1f2406605c8 --- /dev/null +++ b/dbms/tests/queries/0_stateless/01071_in_array.sql @@ -0,0 +1,8 @@ +select [1, 2] in [1, 2]; +select (1, 2) in (1, 2); +select (1, 2) in [(1, 3), (1, 2)]; +select [1] in [[1], [2, 3]]; +select NULL in NULL; +select ([1], [2]) in ([NULL], [NULL]); +select ([1], [2]) in (([NULL], [NULL]), ([1], [2])); +select ([1], [2]) in [([NULL], [NULL]), ([1], [2])]; From c1624f0d9d60da41cceb1b1c1c86157ed2885fcb Mon Sep 17 00:00:00 2001 From: CurtizJ Date: Sat, 25 Jan 2020 00:36:28 +0300 Subject: [PATCH 3/4] strict field casts while making sets --- dbms/src/Interpreters/ActionsVisitor.cpp | 37 ++++++++++++++---------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/dbms/src/Interpreters/ActionsVisitor.cpp b/dbms/src/Interpreters/ActionsVisitor.cpp index b359ef101f0..34cf878399b 100644 --- a/dbms/src/Interpreters/ActionsVisitor.cpp +++ b/dbms/src/Interpreters/ActionsVisitor.cpp @@ -61,7 +61,8 @@ static NamesAndTypesList::iterator findColumn(const String & name, NamesAndTypes [&](const NamesAndTypesList::value_type & val) { return val.name == name; }); } -static Block createBlockFromArray(const Array & array, const DataTypes & types) +template +static Block createBlockFromCollection(const Collection & collection, const DataTypes & types) { size_t columns_num = types.size(); MutableColumns columns(columns_num); @@ -69,7 +70,7 @@ static Block createBlockFromArray(const Array & array, const DataTypes & types) columns[i] = types[i]->createColumn(); Row tuple_values; - for (const auto & value : array) + for (const auto & value : collection) { if (columns_num == 1) { @@ -140,7 +141,7 @@ SetPtr makeExplicitSet( if (prepared_sets.count(set_key)) return prepared_sets.at(set_key); /// Already prepared. - const auto right_arg_evaluated = evaluateConstantExpression(right_arg, context); + auto [right_arg_value, right_arg_type] = evaluateConstantExpression(right_arg, context); std::function getTypeDepth; getTypeDepth = [&getTypeDepth](const DataTypePtr & type) -> size_t @@ -153,31 +154,35 @@ SetPtr makeExplicitSet( return 0; }; - const auto & right_arg_type = right_arg_evaluated.second; - const auto & right_arg_value = right_arg_evaluated.first; - const size_t left_type_depth = getTypeDepth(left_arg_type); const size_t right_type_depth = getTypeDepth(right_arg_type); + auto throw_unsupported_type = [](const auto & type) + { + throw Exception("Unsupported value type at the right-side of IN:" + + type->getName() + ".", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); + }; + Block block; - /// 1 in 1; (1, 2) in (1, 2); identity(tuple(tuple(tuple(1)))) in tuple(tuple(tuple(1))); etc. + /// 1 in 1; (1, 2) in (1, 2); identity(tuple(tuple(tuple(1)))) in tuple(tuple(tuple(1))); etc. if (left_type_depth == right_type_depth) { Array array{right_arg_value}; - block = createBlockFromArray(array, set_element_types); + block = createBlockFromCollection(array, set_element_types); } - /// 1 in (1, 2); (1, 2) in ((1, 2), (3, 4)); etc. + /// 1 in (1, 2); (1, 2) in ((1, 2), (3, 4)); etc. else if (left_type_depth + 1 == right_type_depth) { - const Array & array = DB::safeGet(right_arg_value); - block = createBlockFromArray(array, set_element_types); + auto type_index = right_arg_type->getTypeId(); + if (type_index == TypeIndex::Tuple) + block = createBlockFromCollection(DB::get(right_arg_value), set_element_types); + else if (type_index == TypeIndex::Array) + block = createBlockFromCollection(DB::get(right_arg_value), set_element_types); + else + throw_unsupported_type(right_arg_type); } else - { - throw Exception("Unsupported value type at the right-side of IN:" - + right_arg_type->getName() + ".", - ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); - } + throw_unsupported_type(right_arg_type); SetPtr set = std::make_shared(size_limits, create_ordered_set); From ef2346b0fac00e913d8608bdc2aab52f735fa834 Mon Sep 17 00:00:00 2001 From: alexey-milovidov Date: Sun, 2 Feb 2020 04:33:13 +0300 Subject: [PATCH 4/4] Update ActionsVisitor.cpp --- dbms/src/Interpreters/ActionsVisitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbms/src/Interpreters/ActionsVisitor.cpp b/dbms/src/Interpreters/ActionsVisitor.cpp index 34cf878399b..dbcff2a156c 100644 --- a/dbms/src/Interpreters/ActionsVisitor.cpp +++ b/dbms/src/Interpreters/ActionsVisitor.cpp @@ -159,7 +159,7 @@ SetPtr makeExplicitSet( auto throw_unsupported_type = [](const auto & type) { - throw Exception("Unsupported value type at the right-side of IN:" + throw Exception("Unsupported value type at the right-side of IN: " + type->getName() + ".", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); };