dbms: development [#CONV-2944].

This commit is contained in:
Alexey Milovidov 2011-11-06 02:29:13 +00:00
parent 2b8f400b67
commit c0c2ca630d
8 changed files with 119 additions and 43 deletions

View File

@ -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;
/** Возвращает количество строк в блоке.
* Заодно проверяет, что все столбцы кроме констант (которые содержат единственное значение),
* содержат одинаковое число значений.

View File

@ -29,6 +29,8 @@ public:
private:
StoragePtr getTable();
void setColumns();
/** Пометить часть дерева запроса некоторым part_id.
* - для того, чтобы потом можно было вычислить только часть выражения из запроса.
*/

View File

@ -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;

View File

@ -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;
}
}

View File

@ -43,9 +43,10 @@ void Expression::addSemantic(ASTPtr & ast)
}
}
/// Обход снизу-вверх.
/// Обход снизу-вверх. Не опускаемся в подзапросы.
for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it)
if (!dynamic_cast<ASTSelectQuery *>(&**it))
addSemantic(*it);
if (dynamic_cast<ASTAsterisk *>(&*ast))
@ -119,9 +120,10 @@ void Expression::glueTree(ASTPtr ast)
void Expression::glueTreeImpl(ASTPtr ast, Subtrees & subtrees)
{
/// Обход в глубину
/// Обход в глубину. Не опускаемся в подзапросы.
for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it)
if (!dynamic_cast<ASTSelectQuery *>(&**it))
glueTreeImpl(*it, subtrees);
if (ASTFunction * node = dynamic_cast<ASTFunction *>(&*ast))
@ -164,6 +166,7 @@ void Expression::setNotCalculated(unsigned part_id, ASTPtr subtree)
subtree->calculated = false;
for (ASTs::iterator it = subtree->children.begin(); it != subtree->children.end(); ++it)
if (!dynamic_cast<ASTSelectQuery *>(&**it))
setNotCalculated(part_id, *it);
}
@ -176,9 +179,10 @@ 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)
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)))
@ -232,11 +236,12 @@ 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)
if (!dynamic_cast<ASTSelectQuery *>(&**it))
collectFinalColumns(*it, src, dst, without_duplicates, part_id);
return;
}
@ -250,6 +255,7 @@ 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)
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,6 +282,7 @@ 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)
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)
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,7 +363,9 @@ void Expression::getAggregateInfoImpl(ASTPtr ast, Names & key_names, AggregateDe
}
}
/// Обход в глубину. Не опускаемся в подзапросы.
for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it)
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,6 +409,7 @@ 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)
if (!dynamic_cast<ASTSelectQuery *>(&**it))
markBeforeAndAfterAggregationImpl(*it, before_part_id, after_part_id, below);
}

View File

@ -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

View File

@ -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;
/// Какие столбцы читать из этой таблицы
/// Добавляем в контекст список доступных столбцов.
setColumns();
context.columns = table->getColumnsList();
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;

View File

@ -47,19 +47,35 @@ 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))
if (s_lparen.ignore(pos, end, 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 (!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;
@ -73,6 +89,9 @@ bool ParserSelectQuery::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & ex
dynamic_cast<ASTIdentifier &>(*select_query->database).kind = ASTIdentifier::Database;
dynamic_cast<ASTIdentifier &>(*select_query->table).kind = ASTIdentifier::Table;
}
else
return false;
}
/// WHERE expr
if (s_where.ignore(pos, end, expected))