提交 390f3b72 编写于 作者: A Alexey Milovidov

dbms: development [#CONV-2944].

上级 f44f652c
......@@ -54,6 +54,8 @@ public:
ColumnWithNameAndType & getByName(const std::string & name);
const ColumnWithNameAndType & getByName(const std::string & name) const;
bool has(const std::string & name) const;
size_t getPositionByName(const std::string & name) const;
NamesAndTypesList getColumnsList() const;
......
#ifndef DBMS_CORE_EXCEPTION_H
#define DBMS_CORE_EXCEPTION_H
#pragma once
#include <Poco/Exception.h>
#include <DB/Core/StackTrace.h>
namespace DB
{
/** Тип исключения, чтобы отличать его от других.
*/
POCO_DECLARE_EXCEPTION(Foundation_API, Exception, Poco::Exception);
}
class Exception : public Poco::Exception
{
public:
Exception(int code = 0);
Exception(const std::string & msg, int code = 0);
Exception(const std::string & msg, const std::string & arg, int code = 0);
Exception(const std::string & msg, const Exception & exc, int code = 0);
Exception(const Exception & exc);
~Exception() throw();
Exception & operator = (const Exception & exc);
const char * name() const throw();
const char * className() const throw();
Exception * clone() const;
void rethrow() const;
const StackTrace & getStackTrace() const { return trace; }
#endif
private:
StackTrace trace;
};
}
#pragma once
#include <string>
#include <vector>
namespace DB
{
/// Позволяет получить стек-трейс
class StackTrace
{
public:
/// Стектрейс снимается в момент создания объекта
StackTrace();
/// Вывести в строку
std::string toString() const;
private:
typedef void* Frame;
typedef std::vector<Frame> Frames;
Frames frames;
};
}
......@@ -30,7 +30,7 @@ public:
pool.wait();
if (exception)
throw *exception;
exception->rethrow();
Block res = block;
if (!res)
......
......@@ -16,18 +16,14 @@ using Poco::SharedPtr;
* Выражение состоит из идентификаторов столбцов из блока, констант, обычных функций.
* Например: hits * 2 + 3, instr("yandex", url)
* Выражение не меняет количество строк в потоке, и обрабатывает каждую строку независимо от других.
* is_first - если часть вычислений является первой для блока.
* В этом случае, перед обработкой каждого блока, сбрасываются флаги, что элемент в дереве запроса уже был вычислен.
* При вложенных применениях нескольких ExpressionBlockInputStream, нужно указать is_first только у первого,
* чтобы у последующих не дублировались вычисления.
* part_id - идентификатор части выражения, которую надо вычислять.
* Например, может потребоваться вычислить только часть выражения в секции WHERE.
*/
class ExpressionBlockInputStream : public IProfilingBlockInputStream
{
public:
ExpressionBlockInputStream(BlockInputStreamPtr input_, SharedPtr<Expression> expression_, bool is_first_ = true, unsigned part_id_ = 0)
: input(input_), expression(expression_), is_first(is_first_), part_id(part_id_)
ExpressionBlockInputStream(BlockInputStreamPtr input_, SharedPtr<Expression> expression_, unsigned part_id_ = 0)
: input(input_), expression(expression_), part_id(part_id_)
{
children.push_back(input);
}
......@@ -38,21 +34,17 @@ public:
if (!res)
return res;
if (is_first)
expression->setNotCalculated(part_id);
expression->execute(res, part_id);
return res;
}
String getName() const { return "ExpressionBlockInputStream"; }
BlockInputStreamPtr clone() { return new ExpressionBlockInputStream(input, expression, is_first, part_id); }
BlockInputStreamPtr clone() { return new ExpressionBlockInputStream(input, expression, part_id); }
private:
BlockInputStreamPtr input;
SharedPtr<Expression> expression;
bool is_first;
unsigned part_id;
};
......
......@@ -18,7 +18,7 @@ namespace DB
class Expression
{
public:
Expression(ASTPtr ast_, const Context & context_) : ast(ast_), context(context_)
Expression(const ASTPtr & ast_, const Context & context_) : ast(ast_), context(context_)
{
createAliasesDict(ast);
addSemantic(ast);
......@@ -29,11 +29,6 @@ public:
*/
Names getRequiredColumns();
/** Прописать во всех узлах, что они ещё не вычислены.
* Вызывайте в начале серии вычислений, для каждого блока.
*/
void setNotCalculated(unsigned part_id = 0, ASTPtr subtree = NULL);
/** Выполнить выражение над блоком. Блок должен содержать все столбцы - идентификаторы.
* Функция добавляет в блок новые столбцы - результаты вычислений.
* part_id - какую часть выражения вычислять.
......
......@@ -14,6 +14,7 @@ public:
ASTAsterisk() {}
ASTAsterisk(StringRange range_) : IAST(range_) {}
String getID() { return "Asterisk"; }
ASTPtr clone() const { return new ASTAsterisk(*this); }
};
}
......@@ -28,6 +28,18 @@ public:
/** Получить текст, который идентифицирует этот элемент. */
String getID() { return (attach ? "AttachQuery_" : "CreateQuery_") + database + "_" + table; };
ASTPtr clone() const
{
ASTCreateQuery * res = new ASTCreateQuery(*this);
res->children.clear();
if (columns) { res->columns = columns->clone(); res->children.push_back(res->columns); }
if (storage) { res->storage = storage->clone(); res->children.push_back(res->storage); }
if (select) { res->select = select->clone(); res->children.push_back(res->select); }
return res;
}
};
}
......@@ -22,6 +22,8 @@ public:
/** Получить текст, который идентифицирует этот элемент. */
String getID() { return (detach ? "DetachQuery_" : "DropQuery_") + database + "_" + table; };
ASTPtr clone() const { return new ASTDropQuery(*this); }
};
}
......@@ -19,6 +19,17 @@ public:
/** Получить текст, который идентифицирует этот элемент. */
String getID() { return "ExpressionList"; }
ASTPtr clone() const
{
ASTExpressionList * res = new ASTExpressionList(*this);
res->children.clear();
for (ASTs::const_iterator it = children.begin(); it != children.end(); ++it)
res->children.push_back((*it)->clone());
return res;
}
};
}
......@@ -50,6 +50,16 @@ public:
/** Получить текст, который идентифицирует этот элемент. */
String getID() { return "Function_" + name; }
ASTPtr clone() const
{
ASTFunction * res = new ASTFunction(*this);
res->children.clear();
if (arguments) { res->arguments = arguments->clone(); res->children.push_back(res->arguments); }
return res;
}
};
}
......@@ -40,6 +40,8 @@ public:
/** Получить текст, который идентифицирует этот элемент. */
String getID() { return "Identifier_" + name; }
ASTPtr clone() const { return new ASTIdentifier(*this); }
};
}
......@@ -27,6 +27,17 @@ public:
/** Получить текст, который идентифицирует этот элемент. */
String getID() { return "InsertQuery_" + database + "_" + table; };
ASTPtr clone() const
{
ASTInsertQuery * res = new ASTInsertQuery(*this);
res->children.clear();
if (columns) { res->columns = columns->clone(); res->children.push_back(res->columns); }
if (select) { res->select = select->clone(); res->children.push_back(res->select); }
return res;
}
};
}
......@@ -28,6 +28,8 @@ public:
/** Получить текст, который идентифицирует этот элемент. */
String getID() { return "Literal_" + boost::apply_visitor(FieldVisitorDump(), value); }
ASTPtr clone() const { return new ASTLiteral(*this); }
};
}
......@@ -22,6 +22,16 @@ public:
/** Получить текст, который идентифицирует этот элемент. */
String getID() { return "NameTypePair_" + name; }
ASTPtr clone() const
{
ASTNameTypePair * res = new ASTNameTypePair(*this);
res->children.clear();
if (type) { res->type = type->clone(); res->children.push_back(res->type); }
return res;
}
};
}
......
......@@ -21,6 +21,8 @@ public:
/** Получить текст, который идентифицирует этот элемент. */
String getID() { return "OrderByElement"; }
ASTPtr clone() const { return new ASTOrderByElement(*this); }
};
}
......@@ -28,6 +28,25 @@ public:
/** Получить текст, который идентифицирует этот элемент. */
String getID() { return "SelectQuery"; };
ASTPtr clone() const
{
ASTSelectQuery * res = new ASTSelectQuery(*this);
res->children.clear();
if (select_expression_list) { res->select_expression_list = select_expression_list->clone(); res->children.push_back(res->select_expression_list); }
if (database) { res->database = database->clone(); res->children.push_back(res->database); }
if (table) { res->table = table->clone(); res->children.push_back(res->table); }
if (where_expression) { res->where_expression = where_expression->clone(); res->children.push_back(res->where_expression); }
if (group_expression_list) { res->group_expression_list = group_expression_list->clone(); res->children.push_back(res->group_expression_list); }
if (having_expression) { res->having_expression = having_expression->clone(); res->children.push_back(res->having_expression); }
if (order_expression_list) { res->order_expression_list = order_expression_list->clone(); res->children.push_back(res->order_expression_list); }
if (limit_offset) { res->limit_offset = limit_offset->clone(); res->children.push_back(res->limit_offset); }
if (limit_length) { res->limit_length = limit_length->clone(); res->children.push_back(res->limit_length); }
if (format) { res->format = format->clone(); res->children.push_back(res->format); }
return res;
}
};
}
......@@ -26,19 +26,14 @@ public:
ASTs children;
StringRange range;
/** Было ли соответствующее выражение вычислено.
* Используется, чтобы при обходе графа выражения, не вычислять несколько раз одни и те же узлы.
*/
bool calculated;
/** Идентификатор части выражения. Используется при интерпретации, чтобы вычислять не всё выражение сразу,
* а по частям (например, сначала WHERE, потом фильтрация, потом всё остальное).
*/
unsigned part_id;
IAST() : range(NULL, NULL), calculated(false), part_id(0) {}
IAST(StringRange range_) : range(range_), calculated(false), part_id(0) {}
IAST() : range(NULL, NULL), part_id(0) {}
IAST(StringRange range_) : range(range_), part_id(0) {}
virtual ~IAST() {}
/** Получить каноническое имя столбца, если элемент является столбцом */
......@@ -50,6 +45,9 @@ public:
/** Получить текст, который идентифицирует этот элемент. */
virtual String getID() = 0;
/** Получить глубокую копию дерева. */
virtual SharedPtr<IAST> clone() const = 0;
/** Получить текст, который идентифицирует этот элемент и всё поддерево.
* Обычно он содержит идентификатор элемента и getTreeID от всех детей.
*/
......@@ -76,7 +74,7 @@ public:
void dumpTree(std::ostream & ostr, size_t indent = 0)
{
String indent_str(indent, '-');
ostr << indent_str << getID() << ", " << this << ", part_id = " << part_id << ", calculated = " << calculated << std::endl;
ostr << indent_str << getID() << ", " << this << ", part_id = " << part_id << std::endl;
for (ASTs::iterator it = children.begin(); it != children.end(); ++it)
(*it)->dumpTree(ostr, indent + 1);
}
......
......@@ -128,6 +128,12 @@ const ColumnWithNameAndType & Block::getByName(const std::string & name) const
}
bool Block::has(const std::string & name) const
{
return index_by_name.end() != index_by_name.find(name);
}
size_t Block::getPositionByName(const std::string & name) const
{
IndexByName_t::const_iterator it = index_by_name.find(name);
......
#include <typeinfo>
#include <DB/Core/Exception.h>
namespace DB
{
POCO_IMPLEMENT_EXCEPTION(Exception, Poco::Exception, "DB::Exception");
Exception::Exception(int code): Poco::Exception(code) {}
Exception::Exception(const std::string & msg, int code) : Poco::Exception(msg, code) {}
Exception::Exception(const std::string & msg, const std::string & arg, int code): Poco::Exception(msg, arg, code) {}
Exception::Exception(const std::string & msg, const Exception & exc, int code): Poco::Exception(msg, exc, code), trace(exc.trace) {}
Exception::Exception(const Exception & exc) : Poco::Exception(exc), trace(exc.trace) {}
Exception::~Exception() throw() {}
Exception & Exception::operator=(const Exception& exc)
{
Poco::Exception::operator=(exc);
trace = exc.trace;
return *this;
}
const char* Exception::name() const throw()
{
return "DB::Exception";
}
const char* Exception::className() const throw()
{
return "DB::Exception";
}
Exception * Exception::clone() const
{
return new Exception(*this);
}
void Exception::rethrow() const
{
throw *this;
}
}
#include <malloc.h>
#include <execinfo.h>
#include <cxxabi.h>
#include <string.h>
#include <sstream>
#include <DB/Core/StackTrace.h>
#define DBMS_STACK_TRACE_MAX_DEPTH 32
namespace DB
{
StackTrace::StackTrace()
{
frames.resize(DBMS_STACK_TRACE_MAX_DEPTH);
frames.resize(backtrace(&frames[0], frames.size()));
}
std::string StackTrace::toString() const
{
char ** symbols = backtrace_symbols(&frames[0], frames.size());
std::stringstream res;
if (!symbols)
return "Cannot get symbols for stack trace.\n";
try
{
for (size_t i = 0, size = frames.size(); i < size; ++i)
{
/// Делаем demangling имён. Имя находится в скобках, до символа '+'.
char * name_start = NULL;
char * name_end = NULL;
char * demangled_name = NULL;
int status = 0;
if (NULL != (name_start = strchr(symbols[i], '('))
&& NULL != (name_end = strchr(name_start, '+')))
{
++name_start;
*name_end = '\0';
demangled_name = abi::__cxa_demangle(name_start, 0, 0, &status);
*name_end = '+';
}
try
{
res << i << ". ";
if (NULL != demangled_name && 0 == status)
{
res.write(symbols[i], name_start - symbols[i]);
res << demangled_name << name_end;
}
else
res << symbols[i];
res << std::endl;
}
catch (...)
{
free(demangled_name);
throw;
}
free(demangled_name);
}
}
catch (...)
{
free(symbols);
throw;
}
free(symbols);
return res.str();
}
}
#include <iostream>
#include <DB/Core/StackTrace.h>
int main(int argc, char ** argv)
{
DB::StackTrace trace;
std::cerr << trace.toString();
return 0;
}
......@@ -92,7 +92,7 @@ Block IProfilingBlockInputStream::read()
{
std::cerr << std::endl;
std::cerr << getName() << std::endl;
getInfo().print(std::cerr);
std::cerr << res.dumpNames() << std::endl;
}*/
return res;
......
......@@ -196,19 +196,6 @@ Names Expression::getRequiredColumns()
}
void Expression::setNotCalculated(unsigned part_id, ASTPtr subtree)
{
if (!subtree)
subtree = ast;
subtree->calculated = false;
for (ASTs::iterator it = subtree->children.begin(); it != subtree->children.end(); ++it)
if (!dynamic_cast<ASTSelectQuery *>(&**it))
setNotCalculated(part_id, *it);
}
void Expression::execute(Block & block, unsigned part_id)
{
executeImpl(ast, block, part_id);
......@@ -217,13 +204,17 @@ void Expression::execute(Block & block, unsigned part_id)
void Expression::executeImpl(ASTPtr ast, Block & block, unsigned part_id)
{
/// Обход в глубину. Не опускаемся в подзапросы.
/// Если результат вычисления уже есть в блоке.
if ((dynamic_cast<ASTFunction *>(&*ast) || dynamic_cast<ASTLiteral *>(&*ast)) && block.has(ast->getColumnName()))
return;
/// Обход в глубину. Не опускаемся в подзапросы.
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)))
/// Если это - не указанная часть дерева.
if (!((ast->part_id & part_id) || (ast->part_id == 0 && part_id == 0)))
return;
/** Столбцы из таблицы уже загружены в блок.
......@@ -259,8 +250,6 @@ void Expression::executeImpl(ASTPtr ast, Block & block, unsigned part_id)
block.insert(column);
}
ast->calculated = true;
}
......
......@@ -149,15 +149,12 @@ BlockInputStreamPtr InterpreterSelectQuery::execute()
else
stream = new AsynchronousBlockInputStream(interpreter_subquery->execute());
bool is_first_expression = true;
/// Если есть условие WHERE - сначала выполним часть выражения, необходимую для его вычисления
if (query.where_expression)
{
setPartID(query.where_expression, PART_WHERE);
stream = new AsynchronousBlockInputStream(new ExpressionBlockInputStream(stream, expression, is_first_expression, PART_WHERE));
stream = new AsynchronousBlockInputStream(new ExpressionBlockInputStream(stream, expression, PART_WHERE));
stream = new AsynchronousBlockInputStream(new FilterBlockInputStream(stream));
is_first_expression = false;
}
/// Если есть GROUP BY - сначала выполним часть выражения, необходимую для его вычисления
......@@ -168,27 +165,24 @@ BlockInputStreamPtr InterpreterSelectQuery::execute()
if (query.group_expression_list)
setPartID(query.group_expression_list, PART_GROUP);
stream = new AsynchronousBlockInputStream(new ExpressionBlockInputStream(stream, expression, is_first_expression, PART_GROUP | PART_BEFORE_AGGREGATING));
stream = new AsynchronousBlockInputStream(new ExpressionBlockInputStream(stream, expression, PART_GROUP | PART_BEFORE_AGGREGATING));
stream = new AsynchronousBlockInputStream(new AggregatingBlockInputStream(stream, expression));
stream = new AsynchronousBlockInputStream(new FinalizingAggregatedBlockInputStream(stream));
is_first_expression = false;
}
/// Если есть условие HAVING - сначала выполним часть выражения, необходимую для его вычисления
if (query.having_expression)
{
setPartID(query.having_expression, PART_HAVING);
stream = new AsynchronousBlockInputStream(new ExpressionBlockInputStream(stream, expression, is_first_expression, PART_HAVING));
stream = new AsynchronousBlockInputStream(new ExpressionBlockInputStream(stream, expression, PART_HAVING));
stream = new AsynchronousBlockInputStream(new FilterBlockInputStream(stream));
is_first_expression = false;
}
/// Выполним оставшуюся часть выражения
setPartID(query.select_expression_list, PART_SELECT);
if (query.order_expression_list)
setPartID(query.order_expression_list, PART_ORDER);
stream = new AsynchronousBlockInputStream(new ExpressionBlockInputStream(stream, expression, is_first_expression, PART_SELECT | PART_ORDER));
is_first_expression = false;
stream = new AsynchronousBlockInputStream(new ExpressionBlockInputStream(stream, expression, PART_SELECT | PART_ORDER));
/** Оставим только столбцы, нужные для SELECT и ORDER BY части.
* Если нет ORDER BY - то это последняя проекция, и нужно брать только столбцы из SELECT части.
......
......@@ -204,7 +204,10 @@ int main(int argc, char ** argv)
}
catch (const DB::Exception & e)
{
std::cerr << e.what() << ", " << e.message() << std::endl;
std::cerr << e.what() << ", " << e.message() << std::endl
<< std::endl
<< "Stack trace:" << std::endl
<< e.getStackTrace().toString();
return 1;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册