From c1291e93483a3d5a6174c3a00e00225613e5b746 Mon Sep 17 00:00:00 2001 From: Anton Popov Date: Tue, 24 Mar 2020 15:55:35 +0300 Subject: [PATCH] tuple as literal --- .../evaluateConstantExpression.cpp | 69 ++++++++++++------- dbms/src/Parsers/ExpressionElementParsers.cpp | 14 ++-- dbms/src/Parsers/ExpressionElementParsers.h | 1 + .../Processors/Executors/PipelineExecutor.h | 1 + .../Impl/ConstantExpressionTemplate.cpp | 47 ++++++++++--- 5 files changed, 90 insertions(+), 42 deletions(-) diff --git a/dbms/src/Interpreters/evaluateConstantExpression.cpp b/dbms/src/Interpreters/evaluateConstantExpression.cpp index 37e990fd5fc..fd5e2475df1 100644 --- a/dbms/src/Interpreters/evaluateConstantExpression.cpp +++ b/dbms/src/Interpreters/evaluateConstantExpression.cpp @@ -101,9 +101,9 @@ namespace using Conjunction = ColumnsWithTypeAndName; using Disjunction = std::vector; - Disjunction analyzeEquals(const ASTIdentifier * identifier, const ASTLiteral * literal, const ExpressionActionsPtr & expr) + Disjunction analyzeEquals(const ASTIdentifier * identifier, const Field & value, const ExpressionActionsPtr & expr) { - if (!identifier || !literal) + if (!identifier || value.isNull()) { return {}; } @@ -117,7 +117,7 @@ namespace { ColumnWithTypeAndName column; // FIXME: what to do if field is not convertable? - column.column = type->createColumnConst(1, convertFieldToType(literal->value, *type)); + column.column = type->createColumnConst(1, convertFieldToType(value, *type)); column.name = name; column.type = type; return {{std::move(column)}}; @@ -127,6 +127,16 @@ namespace return {}; } + Disjunction analyzeEquals(const ASTIdentifier * identifier, const ASTLiteral * literal, const ExpressionActionsPtr & expr) + { + if (!identifier || !literal) + { + return {}; + } + + return analyzeEquals(identifier, literal->value, expr); + } + Disjunction andDNF(const Disjunction & left, const Disjunction & right) { if (left.empty()) @@ -172,33 +182,44 @@ namespace const auto * left = fn->arguments->children.front().get(); const auto * right = fn->arguments->children.back().get(); const auto * identifier = left->as(); - const auto * inner_fn = right->as(); - - if (!inner_fn) - { - return {}; - } - - const auto * tuple = inner_fn->children.front()->as(); - - if (!tuple) - { - return {}; - } Disjunction result; - for (const auto & child : tuple->children) + if (const auto * tuple_func = right->as(); tuple_func && tuple_func->name == "tuple") { - const auto * literal = child->as(); - const auto dnf = analyzeEquals(identifier, literal, expr); - - if (dnf.empty()) + const auto * tuple_elements = tuple_func->children.front()->as(); + for (const auto & child : tuple_elements->children) { - return {}; - } + const auto * literal = child->as(); + const auto dnf = analyzeEquals(identifier, literal, expr); - result.insert(result.end(), dnf.begin(), dnf.end()); + if (dnf.empty()) + { + return {}; + } + + result.insert(result.end(), dnf.begin(), dnf.end()); + } + } + else if (const auto * tuple_literal = right->as(); + tuple_literal && tuple_literal->value.getType() == Field::Types::Tuple) + { + const auto & tuple = tuple_literal->value.get(); + for (const auto & child : tuple) + { + const auto dnf = analyzeEquals(identifier, child, expr); + + if (dnf.empty()) + { + return {}; + } + + result.insert(result.end(), dnf.begin(), dnf.end()); + } + } + else + { + return {}; } return result; diff --git a/dbms/src/Parsers/ExpressionElementParsers.cpp b/dbms/src/Parsers/ExpressionElementParsers.cpp index af676d94f77..59c63f89189 100644 --- a/dbms/src/Parsers/ExpressionElementParsers.cpp +++ b/dbms/src/Parsers/ExpressionElementParsers.cpp @@ -999,11 +999,9 @@ bool ParserCollectionOfLiterals::parseImpl(Pos & pos, ASTPtr & node, Pos literal_begin = pos; Collection arr; - ParserLiteral literal_p; ++pos; - while (pos.isValid()) { if (!arr.empty()) @@ -1012,12 +1010,11 @@ bool ParserCollectionOfLiterals::parseImpl(Pos & pos, ASTPtr & node, { std::shared_ptr literal; - /// Parse one-element tuples (e.g. (1)) as single values for backward compatibility. + /// Parse one-element tuples (e.g. (1)) later as single values for backward compatibility. if (std::is_same_v && arr.size() == 1) - literal = std::make_shared(arr[0]); - else - literal = std::make_shared(arr); + return false; + literal = std::make_shared(arr); literal->begin = literal_begin; literal->end = ++pos; node = literal; @@ -1029,9 +1026,8 @@ bool ParserCollectionOfLiterals::parseImpl(Pos & pos, ASTPtr & node, } else { - std::stringstream msg; - msg << "comma or " << getTokenName(closing_bracket); - expected.add(pos, msg.str().c_str()); + String message = String("comma or ") + getTokenName(closing_bracket); + expected.add(pos, message.c_str()); return false; } } diff --git a/dbms/src/Parsers/ExpressionElementParsers.h b/dbms/src/Parsers/ExpressionElementParsers.h index b2923118225..b9d8d5db42c 100644 --- a/dbms/src/Parsers/ExpressionElementParsers.h +++ b/dbms/src/Parsers/ExpressionElementParsers.h @@ -239,6 +239,7 @@ private: TokenType closing_bracket; }; +/// A tuple of literals with same type. class ParserTupleOfLiterals : public IParserBase { public: diff --git a/dbms/src/Processors/Executors/PipelineExecutor.h b/dbms/src/Processors/Executors/PipelineExecutor.h index 673151bd5eb..20569d974ee 100644 --- a/dbms/src/Processors/Executors/PipelineExecutor.h +++ b/dbms/src/Processors/Executors/PipelineExecutor.h @@ -273,6 +273,7 @@ private: void executeSingleThread(size_t thread_num, size_t num_threads); void finish(); +public: String dumpPipeline() const; }; diff --git a/dbms/src/Processors/Formats/Impl/ConstantExpressionTemplate.cpp b/dbms/src/Processors/Formats/Impl/ConstantExpressionTemplate.cpp index 83e449ee368..07506f7ca8e 100644 --- a/dbms/src/Processors/Formats/Impl/ConstantExpressionTemplate.cpp +++ b/dbms/src/Processors/Formats/Impl/ConstantExpressionTemplate.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -148,11 +149,18 @@ private: info.type = std::make_shared(); else if (field_type == Field::Types::String) info.type = std::make_shared(); - else if (field_type == Field::Types::Array) + else if (field_type == Field::Types::Array || field_type == Field::Types::Tuple) { info.special_parser.is_array = true; info.type = applyVisitor(FieldToDataType(), info.literal->value); - auto nested_type = assert_cast(*info.type).getNestedType(); + + DataTypePtr nested_type; + if (auto array_type = typeid_cast(info.type.get())) + nested_type = array_type->getNestedType(); + else if (auto tuple_type = typeid_cast(info.type.get())) + nested_type = tuple_type->getElements()[0]; + else + throw Exception("Unexpected type " + info.type->getName(), ErrorCodes::LOGICAL_ERROR); /// It can be Array(Nullable(nested_type)) bool array_of_nullable = false; @@ -192,7 +200,18 @@ private: info.special_parser.is_nullable = true; } - info.type = std::make_shared(nested_type); + if (field_type == Field::Types::Tuple) + { + const auto & tuple = info.literal->value.get(); + DataTypes elements(tuple.size()); + for (size_t i = 0; i < tuple.size(); ++i) + elements[i] = nested_type; + info.type = std::make_shared(elements); + } + else + { + info.type = std::make_shared(nested_type); + } } else throw Exception(String("Unexpected literal type ") + info.literal->value.getTypeName() + ". It's a bug", @@ -408,18 +427,28 @@ bool ConstantExpressionTemplate::parseLiteralAndAssertType(ReadBuffer & istr, co { /// TODO faster way to check types without using Parsers ParserArrayOfLiterals parser_array; + ParserTupleOfLiterals parser_tuple; + Tokens tokens_number(istr.position(), istr.buffer().end()); IParser::Pos iterator(tokens_number, settings.max_parser_depth); Expected expected; ASTPtr ast; - - if (!parser_array.parse(iterator, ast, expected)) + if (!parser_array.parse(iterator, ast, expected) && !parser_tuple.parse(iterator, ast, expected)) return false; istr.position() = const_cast(iterator->begin); - const Field & array = ast->as().value; - auto array_type = applyVisitor(FieldToDataType(), array); - auto nested_type = assert_cast(*array_type).getNestedType(); + const Field & collection = ast->as().value; + auto collection_type = applyVisitor(FieldToDataType(), collection); + + DataTypePtr nested_type; + if (auto array_type = typeid_cast(collection_type.get())) + nested_type = array_type->getNestedType(); + else if (auto tuple_type = typeid_cast(collection_type.get())) + nested_type = tuple_type->getElements()[0]; + + if (!nested_type) + return false; + if (type_info.is_nullable) if (auto nullable = dynamic_cast(nested_type.get())) nested_type = nullable->getNestedType(); @@ -429,7 +458,7 @@ bool ConstantExpressionTemplate::parseLiteralAndAssertType(ReadBuffer & istr, co (nested_type_info.isNativeInt() && type_info.nested_type == Type::Int64) || (nested_type_info.isFloat64() && type_info.nested_type == Type::Float64)) { - Field array_same_types = convertFieldToType(array, *complex_type, nullptr); + Field array_same_types = convertFieldToType(collection, *complex_type, nullptr); columns[column_idx]->insert(array_same_types); return true; }