mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-20 00:30:49 +00:00
dbms: development [#CONV-2944].
This commit is contained in:
parent
2b8f400b67
commit
c0c2ca630d
@ -5,6 +5,7 @@
|
||||
#include <list>
|
||||
|
||||
#include <DB/Core/ColumnWithNameAndType.h>
|
||||
#include <DB/Core/NamesAndTypes.h>
|
||||
#include <DB/Core/Exception.h>
|
||||
#include <DB/Core/ErrorCodes.h>
|
||||
|
||||
@ -55,6 +56,8 @@ public:
|
||||
|
||||
size_t getPositionByName(const std::string & name) const;
|
||||
|
||||
NamesAndTypesList getColumnsList() const;
|
||||
|
||||
/** Возвращает количество строк в блоке.
|
||||
* Заодно проверяет, что все столбцы кроме констант (которые содержат единственное значение),
|
||||
* содержат одинаковое число значений.
|
||||
|
@ -28,6 +28,8 @@ public:
|
||||
|
||||
private:
|
||||
StoragePtr getTable();
|
||||
|
||||
void setColumns();
|
||||
|
||||
/** Пометить часть дерева запроса некоторым part_id.
|
||||
* - для того, чтобы потом можно было вычислить только часть выражения из запроса.
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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<ASTSelectQuery *>(&**it))
|
||||
addSemantic(*it);
|
||||
|
||||
if (dynamic_cast<ASTAsterisk *>(&*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<ASTSelectQuery *>(&**it))
|
||||
glueTreeImpl(*it, subtrees);
|
||||
|
||||
if (ASTFunction * node = dynamic_cast<ASTFunction *>(&*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<ASTSelectQuery *>(&**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<ASTSelectQuery *>(&**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<ASTFunction *>(&*ast))
|
||||
for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it)
|
||||
collectFinalColumns(*it, src, dst, without_duplicates, part_id);
|
||||
if (!dynamic_cast<ASTSelectQuery *>(&**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<ASTSelectQuery *>(&**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<ASTIdentifier *>(&*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<ASTSelectQuery *>(&**it))
|
||||
getReturnTypesImpl(*it, res);
|
||||
}
|
||||
|
||||
|
||||
@ -292,7 +299,7 @@ void Expression::getSampleBlockImpl(ASTPtr ast, Block & res)
|
||||
{
|
||||
ColumnWithNameAndType col;
|
||||
|
||||
/// Обход в глубину, который не заходит внутрь функций.
|
||||
/// Обход в глубину, который не заходит внутрь функций и подзапросов.
|
||||
if (ASTIdentifier * ident = dynamic_cast<ASTIdentifier *>(&*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<ASTSelectQuery *>(&**it))
|
||||
getSampleBlockImpl(*it, res);
|
||||
}
|
||||
|
||||
|
||||
void Expression::getAggregateInfoImpl(ASTPtr ast, Names & key_names, AggregateDescriptions & aggregates, NamesSet & processed)
|
||||
{
|
||||
/// Обход в глубину
|
||||
if (ASTSelectQuery * select = dynamic_cast<ASTSelectQuery *>(&*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<ASTSelectQuery *>(&**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<ASTSelectQuery *>(&**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<ASTSelectQuery *>(&**it))
|
||||
markBeforeAndAfterAggregationImpl(*it, before_part_id, after_part_id, below);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -62,9 +62,22 @@ StoragePtr InterpreterSelectQuery::getTable()
|
||||
}
|
||||
|
||||
|
||||
void InterpreterSelectQuery::setColumns()
|
||||
{
|
||||
ASTSelectQuery & query = dynamic_cast<ASTSelectQuery &>(*query_ptr);
|
||||
|
||||
context.columns = dynamic_cast<ASTIdentifier *>(&*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<ASTSelectQuery &>(*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<ASTSelectQuery &>(*query_ptr).select_expression_list, context);
|
||||
return expression.getSampleBlock();
|
||||
}
|
||||
@ -82,17 +95,30 @@ BlockInputStreamPtr InterpreterSelectQuery::execute()
|
||||
{
|
||||
ASTSelectQuery & query = dynamic_cast<ASTSelectQuery &>(*query_ptr);
|
||||
|
||||
StoragePtr table = getTable();
|
||||
|
||||
/// Какие столбцы читать из этой таблицы
|
||||
/// Таблица, откуда читать данные, если не подзапрос.
|
||||
StoragePtr table;
|
||||
/// Интерпретатор подзапроса, если подзапрос
|
||||
SharedPtr<InterpreterSelectQuery> interpreter_subquery;
|
||||
|
||||
context.columns = table->getColumnsList();
|
||||
/// Добавляем в контекст список доступных столбцов.
|
||||
setColumns();
|
||||
|
||||
if (dynamic_cast<ASTIdentifier *>(&*query.table))
|
||||
table = getTable();
|
||||
else
|
||||
interpreter_subquery = new InterpreterSelectQuery(query.table, context, max_block_size);
|
||||
|
||||
/// Выражение, с помощью которого анализируется SELECT часть запроса.
|
||||
Poco::SharedPtr<Expression> 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<UInt64>(dynamic_cast<ASTLiteral &>(*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<ASTIdentifier *>(&*query.table))
|
||||
stream = table->read(required_columns, query_ptr, block_size);
|
||||
else
|
||||
stream = interpreter_subquery->execute();
|
||||
|
||||
bool is_first_expression = true;
|
||||
|
||||
|
@ -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<ASTIdentifier &>(*select_query->database).kind = ASTIdentifier::Database;
|
||||
dynamic_cast<ASTIdentifier &>(*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<ASTIdentifier &>(*select_query->database).kind = ASTIdentifier::Database;
|
||||
dynamic_cast<ASTIdentifier &>(*select_query->table).kind = ASTIdentifier::Table;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// WHERE expr
|
||||
|
Loading…
Reference in New Issue
Block a user