From c0c2ca630db4a34d5163e6928552b30c18c78616 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Sun, 6 Nov 2011 02:29:13 +0000 Subject: [PATCH] dbms: development [#CONV-2944]. --- dbms/include/DB/Core/Block.h | 3 ++ .../DB/Interpreters/InterpreterSelectQuery.h | 2 + dbms/include/DB/Parsers/ASTSelectQuery.h | 2 +- dbms/src/Core/Block.cpp | 11 ++++ dbms/src/Interpreters/Expression.cpp | 46 ++++++++++------- .../Interpreters/InterpreterCreateQuery.cpp | 2 +- .../Interpreters/InterpreterSelectQuery.cpp | 51 +++++++++++++++---- dbms/src/Parsers/ParserSelectQuery.cpp | 45 +++++++++++----- 8 files changed, 119 insertions(+), 43 deletions(-) diff --git a/dbms/include/DB/Core/Block.h b/dbms/include/DB/Core/Block.h index a9ee07e2b1b..4b66ab53145 100644 --- a/dbms/include/DB/Core/Block.h +++ b/dbms/include/DB/Core/Block.h @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -55,6 +56,8 @@ public: size_t getPositionByName(const std::string & name) const; + NamesAndTypesList getColumnsList() const; + /** Возвращает количество строк в блоке. * Заодно проверяет, что все столбцы кроме констант (которые содержат единственное значение), * содержат одинаковое число значений. diff --git a/dbms/include/DB/Interpreters/InterpreterSelectQuery.h b/dbms/include/DB/Interpreters/InterpreterSelectQuery.h index 0daa81ef5e5..d6006e89a88 100644 --- a/dbms/include/DB/Interpreters/InterpreterSelectQuery.h +++ b/dbms/include/DB/Interpreters/InterpreterSelectQuery.h @@ -28,6 +28,8 @@ public: private: StoragePtr getTable(); + + void setColumns(); /** Пометить часть дерева запроса некоторым part_id. * - для того, чтобы потом можно было вычислить только часть выражения из запроса. diff --git a/dbms/include/DB/Parsers/ASTSelectQuery.h b/dbms/include/DB/Parsers/ASTSelectQuery.h index 3f3628e9bc3..392ff8b8e54 100644 --- a/dbms/include/DB/Parsers/ASTSelectQuery.h +++ b/dbms/include/DB/Parsers/ASTSelectQuery.h @@ -14,7 +14,7 @@ class ASTSelectQuery : public IAST public: ASTPtr select_expression_list; ASTPtr database; - ASTPtr table; + ASTPtr table; /// Идентификатор или подзапрос (рекурсивно ASTSelectQuery) ASTPtr where_expression; ASTPtr group_expression_list; ASTPtr having_expression; diff --git a/dbms/src/Core/Block.cpp b/dbms/src/Core/Block.cpp index 2fee00395ee..40480a580a5 100644 --- a/dbms/src/Core/Block.cpp +++ b/dbms/src/Core/Block.cpp @@ -192,4 +192,15 @@ Block Block::cloneEmpty() const } +NamesAndTypesList Block::getColumnsList() const +{ + NamesAndTypesList res; + + for (Container_t::const_iterator it = data.begin(); it != data.end(); ++it) + res.push_back(NameAndTypePair(it->name, it->type)); + + return res; +} + + } diff --git a/dbms/src/Interpreters/Expression.cpp b/dbms/src/Interpreters/Expression.cpp index 1f4e1c64c3f..7360562803e 100644 --- a/dbms/src/Interpreters/Expression.cpp +++ b/dbms/src/Interpreters/Expression.cpp @@ -43,10 +43,11 @@ void Expression::addSemantic(ASTPtr & ast) } } - /// Обход снизу-вверх. + /// Обход снизу-вверх. Не опускаемся в подзапросы. for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it) - addSemantic(*it); + if (!dynamic_cast(&**it)) + addSemantic(*it); if (dynamic_cast(&*ast)) { @@ -119,10 +120,11 @@ void Expression::glueTree(ASTPtr ast) void Expression::glueTreeImpl(ASTPtr ast, Subtrees & subtrees) { - /// Обход в глубину + /// Обход в глубину. Не опускаемся в подзапросы. for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it) - glueTreeImpl(*it, subtrees); + if (!dynamic_cast(&**it)) + glueTreeImpl(*it, subtrees); if (ASTFunction * node = dynamic_cast(&*ast)) { @@ -164,7 +166,8 @@ void Expression::setNotCalculated(unsigned part_id, ASTPtr subtree) subtree->calculated = false; for (ASTs::iterator it = subtree->children.begin(); it != subtree->children.end(); ++it) - setNotCalculated(part_id, *it); + if (!dynamic_cast(&**it)) + setNotCalculated(part_id, *it); } @@ -176,10 +179,11 @@ void Expression::execute(Block & block, unsigned part_id) void Expression::executeImpl(ASTPtr ast, Block & block, unsigned part_id) { - /// Обход в глубину + /// Обход в глубину. Не опускаемся в подзапросы. for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it) - executeImpl(*it, block, part_id); + if (!dynamic_cast(&**it)) + executeImpl(*it, block, part_id); if (ast->calculated || !((ast->part_id & part_id) || (ast->part_id == 0 && part_id == 0))) return; @@ -232,12 +236,13 @@ Block Expression::projectResult(Block & block, bool without_duplicates, unsigned void Expression::collectFinalColumns(ASTPtr ast, Block & src, Block & dst, bool without_duplicates, unsigned part_id) { - /// Обход в глубину, который не заходит внутрь функций. + /// Обход в глубину, который не заходит внутрь функций и подзапросов. if (!((ast->part_id & part_id) || (ast->part_id == 0 && part_id == 0))) { if (!dynamic_cast(&*ast)) for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it) - collectFinalColumns(*it, src, dst, without_duplicates, part_id); + if (!dynamic_cast(&**it)) + collectFinalColumns(*it, src, dst, without_duplicates, part_id); return; } @@ -250,7 +255,8 @@ void Expression::collectFinalColumns(ASTPtr ast, Block & src, Block & dst, bool without_duplicates ? dst.insertUnique(src.getByName(ast->getColumnName())) : dst.insert(src.getByName(ast->getColumnName())); else for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it) - collectFinalColumns(*it, src, dst, without_duplicates, part_id); + if (!dynamic_cast(&**it)) + collectFinalColumns(*it, src, dst, without_duplicates, part_id); } @@ -264,7 +270,7 @@ DataTypes Expression::getReturnTypes() void Expression::getReturnTypesImpl(ASTPtr ast, DataTypes & res) { - /// Обход в глубину, который не заходит внутрь функций. + /// Обход в глубину, который не заходит внутрь функций и подзапросов. if (ASTIdentifier * ident = dynamic_cast(&*ast)) { if (ident->kind == ASTIdentifier::Column) @@ -276,7 +282,8 @@ void Expression::getReturnTypesImpl(ASTPtr ast, DataTypes & res) res.push_back(func->return_type); else for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it) - getReturnTypesImpl(*it, res); + if (!dynamic_cast(&**it)) + getReturnTypesImpl(*it, res); } @@ -292,7 +299,7 @@ void Expression::getSampleBlockImpl(ASTPtr ast, Block & res) { ColumnWithNameAndType col; - /// Обход в глубину, который не заходит внутрь функций. + /// Обход в глубину, который не заходит внутрь функций и подзапросов. if (ASTIdentifier * ident = dynamic_cast(&*ast)) { if (ident->kind == ASTIdentifier::Column) @@ -316,13 +323,13 @@ void Expression::getSampleBlockImpl(ASTPtr ast, Block & res) } else for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it) - getSampleBlockImpl(*it, res); + if (!dynamic_cast(&**it)) + getSampleBlockImpl(*it, res); } void Expression::getAggregateInfoImpl(ASTPtr ast, Names & key_names, AggregateDescriptions & aggregates, NamesSet & processed) { - /// Обход в глубину if (ASTSelectQuery * select = dynamic_cast(&*ast)) { if (select->group_expression_list) @@ -356,8 +363,10 @@ void Expression::getAggregateInfoImpl(ASTPtr ast, Names & key_names, AggregateDe } } + /// Обход в глубину. Не опускаемся в подзапросы. for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it) - getAggregateInfoImpl(*it, key_names, aggregates, processed); + if (!dynamic_cast(&**it)) + getAggregateInfoImpl(*it, key_names, aggregates, processed); } @@ -375,7 +384,7 @@ bool Expression::hasAggregatesImpl(ASTPtr ast) return true; for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it) - if (hasAggregatesImpl(*it)) + if (!dynamic_cast(&**it) && hasAggregatesImpl(*it)) return true; return false; @@ -400,7 +409,8 @@ void Expression::markBeforeAndAfterAggregationImpl(ASTPtr ast, unsigned before_p ast->part_id |= after_part_id; for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it) - markBeforeAndAfterAggregationImpl(*it, before_part_id, after_part_id, below); + if (!dynamic_cast(&**it)) + markBeforeAndAfterAggregationImpl(*it, before_part_id, after_part_id, below); } diff --git a/dbms/src/Interpreters/InterpreterCreateQuery.cpp b/dbms/src/Interpreters/InterpreterCreateQuery.cpp index f9e3dc83d51..23ab7223dbb 100644 --- a/dbms/src/Interpreters/InterpreterCreateQuery.cpp +++ b/dbms/src/Interpreters/InterpreterCreateQuery.cpp @@ -42,7 +42,7 @@ StoragePtr InterpreterCreateQuery::execute() String as_table_name = create.as_table; NamesAndTypesListPtr columns = new NamesAndTypesList; - String data_path = context.path + "data/" + database_name_escaped + "/"; /// TODO: эскейпинг + String data_path = context.path + "data/" + database_name_escaped + "/"; String metadata_path = context.path + "metadata/" + database_name_escaped + "/" + (!table_name.empty() ? table_name_escaped + ".sql" : ""); /// CREATE|ATTACH DATABASE diff --git a/dbms/src/Interpreters/InterpreterSelectQuery.cpp b/dbms/src/Interpreters/InterpreterSelectQuery.cpp index 614a7bed629..8ad361b628a 100644 --- a/dbms/src/Interpreters/InterpreterSelectQuery.cpp +++ b/dbms/src/Interpreters/InterpreterSelectQuery.cpp @@ -62,9 +62,22 @@ StoragePtr InterpreterSelectQuery::getTable() } +void InterpreterSelectQuery::setColumns() +{ + ASTSelectQuery & query = dynamic_cast(*query_ptr); + + context.columns = dynamic_cast(&*query.table) + ? getTable()->getColumnsList() + : InterpreterSelectQuery(query.table, context, max_block_size).getSampleBlock().getColumnsList(); + + if (context.columns.empty()) + throw Exception("There is no available columns", ErrorCodes::THERE_IS_NO_COLUMN); +} + + DataTypes InterpreterSelectQuery::getReturnTypes() { - context.columns = getTable()->getColumnsList(); + setColumns(); Expression expression(dynamic_cast(*query_ptr).select_expression_list, context); return expression.getReturnTypes(); } @@ -72,7 +85,7 @@ DataTypes InterpreterSelectQuery::getReturnTypes() Block InterpreterSelectQuery::getSampleBlock() { - context.columns = getTable()->getColumnsList(); + setColumns(); Expression expression(dynamic_cast(*query_ptr).select_expression_list, context); return expression.getSampleBlock(); } @@ -82,17 +95,30 @@ BlockInputStreamPtr InterpreterSelectQuery::execute() { ASTSelectQuery & query = dynamic_cast(*query_ptr); - StoragePtr table = getTable(); - - /// Какие столбцы читать из этой таблицы + /// Таблица, откуда читать данные, если не подзапрос. + StoragePtr table; + /// Интерпретатор подзапроса, если подзапрос + SharedPtr interpreter_subquery; - context.columns = table->getColumnsList(); + /// Добавляем в контекст список доступных столбцов. + setColumns(); + + if (dynamic_cast(&*query.table)) + table = getTable(); + else + interpreter_subquery = new InterpreterSelectQuery(query.table, context, max_block_size); + + /// Выражение, с помощью которого анализируется SELECT часть запроса. Poco::SharedPtr expression = new Expression(query_ptr, context); + /// Список столбцов, которых нужно прочитать, чтобы выполнить запрос. Names required_columns = expression->getRequiredColumns(); /// Если не указан ни один столбец из таблицы, то будем читать первый попавшийся (чтобы хотя бы знать число строк). if (required_columns.empty()) - required_columns.push_back(table->getColumnsMap().begin()->first); + required_columns.push_back(context.columns.front().first); + + /// Нужно ли агрегировать. + bool need_aggregate = expression->hasAggregates() || query.group_expression_list; size_t limit_length = 0; size_t limit_offset = 0; @@ -103,8 +129,6 @@ BlockInputStreamPtr InterpreterSelectQuery::execute() limit_offset = boost::get(dynamic_cast(*query.limit_offset).value); } - bool need_aggregate = expression->hasAggregates() || query.group_expression_list; - /** Оптимизация - если не указаны WHERE, GROUP, HAVING, ORDER, но указан LIMIT, и limit + offset < max_block_size, * то в качестве размера блока будем использовать limit + offset (чтобы не читать из таблицы больше, чем запрошено). */ @@ -115,7 +139,14 @@ BlockInputStreamPtr InterpreterSelectQuery::execute() block_size = limit_length + limit_offset; } - BlockInputStreamPtr stream = table->read(required_columns, query_ptr, block_size); + /// Поток данных. + BlockInputStreamPtr stream; + + /// Инициализируем изначальный поток данных, на который накладываются преобразования запроса. Таблица или подзапрос? + if (dynamic_cast(&*query.table)) + stream = table->read(required_columns, query_ptr, block_size); + else + stream = interpreter_subquery->execute(); bool is_first_expression = true; diff --git a/dbms/src/Parsers/ParserSelectQuery.cpp b/dbms/src/Parsers/ParserSelectQuery.cpp index 1da896a1613..5425380edee 100644 --- a/dbms/src/Parsers/ParserSelectQuery.cpp +++ b/dbms/src/Parsers/ParserSelectQuery.cpp @@ -47,31 +47,50 @@ bool ParserSelectQuery::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & ex ws.ignore(pos, end); } - /// FROM database.table или FROM table TODO subquery + /// FROM database.table или FROM table или FROM (subquery) if (s_from.ignore(pos, end, expected)) { ws.ignore(pos, end); + ParserString s_lparen("("); + ParserString s_rparen(")"); ParserString s_dot("."); ParserIdentifier ident; - if (!ident.parse(pos, end, select_query->table, expected)) - return false; - - ws.ignore(pos, end); - - if (s_dot.ignore(pos, end, expected)) + if (s_lparen.ignore(pos, end, expected)) { - select_query->database = select_query->table; - if (!ident.parse(pos, end, select_query->table, expected)) + ws.ignore(pos, end); + + ParserSelectQuery select_p; + if (!select_p.parse(pos, end, select_query->table, expected)) return false; ws.ignore(pos, end); - } - if (select_query->database) - dynamic_cast(*select_query->database).kind = ASTIdentifier::Database; - dynamic_cast(*select_query->table).kind = ASTIdentifier::Table; + if (!s_rparen.ignore(pos, end, expected)) + return false; + + ws.ignore(pos, end); + } + else if (ident.parse(pos, end, select_query->table, expected)) + { + ws.ignore(pos, end); + + if (s_dot.ignore(pos, end, expected)) + { + select_query->database = select_query->table; + if (!ident.parse(pos, end, select_query->table, expected)) + return false; + + ws.ignore(pos, end); + } + + if (select_query->database) + dynamic_cast(*select_query->database).kind = ASTIdentifier::Database; + dynamic_cast(*select_query->table).kind = ASTIdentifier::Table; + } + else + return false; } /// WHERE expr