2011-08-09 19:19:00 +00:00
|
|
|
|
#pragma once
|
2010-06-24 19:12:10 +00:00
|
|
|
|
|
|
|
|
|
#include <list>
|
2013-08-13 08:54:28 +00:00
|
|
|
|
#include <set>
|
2011-08-09 19:19:00 +00:00
|
|
|
|
#include <sstream>
|
2015-08-06 04:28:59 +00:00
|
|
|
|
#include <iostream>
|
2015-08-06 21:32:51 +00:00
|
|
|
|
#include <set>
|
2011-08-09 19:19:00 +00:00
|
|
|
|
|
2010-06-24 19:12:10 +00:00
|
|
|
|
#include <Poco/SharedPtr.h>
|
2012-12-26 20:29:28 +00:00
|
|
|
|
|
2015-09-29 19:19:54 +00:00
|
|
|
|
#include <common/Common.h>
|
2010-06-24 19:12:10 +00:00
|
|
|
|
|
|
|
|
|
#include <DB/Core/Types.h>
|
2015-10-05 01:35:28 +00:00
|
|
|
|
#include <DB/Common/Exception.h>
|
2013-06-21 20:34:19 +00:00
|
|
|
|
#include <DB/IO/WriteHelpers.h>
|
2010-06-24 19:12:10 +00:00
|
|
|
|
#include <DB/Parsers/StringRange.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
2016-01-11 21:46:36 +00:00
|
|
|
|
namespace ErrorCodes
|
|
|
|
|
{
|
|
|
|
|
extern const int NOT_A_COLUMN;
|
|
|
|
|
extern const int TOO_BIG_AST;
|
|
|
|
|
extern const int TOO_DEEP_AST;
|
|
|
|
|
extern const int UNKNOWN_TYPE_OF_AST_NODE;
|
|
|
|
|
extern const int UNKNOWN_ELEMENT_IN_AST;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-24 19:12:10 +00:00
|
|
|
|
using Poco::SharedPtr;
|
2016-01-11 21:46:36 +00:00
|
|
|
|
using IdentifierNameSet = std::set<String>;
|
2010-06-24 19:12:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Элемент синтаксического дерева (в дальнейшем - направленного ациклического графа с элементами семантики)
|
|
|
|
|
*/
|
|
|
|
|
class IAST
|
2011-08-13 21:05:18 +00:00
|
|
|
|
{
|
2010-06-24 19:12:10 +00:00
|
|
|
|
public:
|
2016-01-11 21:46:36 +00:00
|
|
|
|
using ASTs = std::vector<SharedPtr<IAST>>;
|
2011-08-13 21:05:18 +00:00
|
|
|
|
ASTs children;
|
|
|
|
|
StringRange range;
|
2015-09-18 13:36:10 +00:00
|
|
|
|
|
|
|
|
|
/// Указатель на начало секции [NOT]IN или JOIN в которой включен этот узел,
|
|
|
|
|
/// если имеется такая секция.
|
|
|
|
|
IAST * enclosing_in_or_join = nullptr;
|
|
|
|
|
|
|
|
|
|
/// Атрибуты, которые нужны для некоторых алгоритмов на синтаксических деревьях.
|
|
|
|
|
using Attributes = UInt32;
|
|
|
|
|
Attributes attributes = 0;
|
|
|
|
|
|
|
|
|
|
/// Был ли узел посещён? (см. класс LogicalExpressionsOptimizer)
|
|
|
|
|
static constexpr Attributes IsVisited = 1U;
|
|
|
|
|
/// Был ли узел обработан? (см. класс InJoinSubqueriesPreprocessor)
|
|
|
|
|
static constexpr Attributes IsPreprocessedForInJoinSubqueries = 1U << 1;
|
|
|
|
|
/// Является ли узел секцией IN?
|
|
|
|
|
static constexpr Attributes IsIn = 1U << 2;
|
|
|
|
|
/// Является ли узел секцией NOT IN?
|
|
|
|
|
static constexpr Attributes IsNotIn = 1U << 3;
|
|
|
|
|
/// Является ли узел секцией JOIN?
|
|
|
|
|
static constexpr Attributes IsJoin = 1U << 4;
|
|
|
|
|
/// Имеет ли секция IN/NOT IN/JOIN атрибут GLOBAL?
|
|
|
|
|
static constexpr Attributes IsGlobal = 1U << 5;
|
|
|
|
|
|
2016-02-02 11:49:57 +00:00
|
|
|
|
/** Глубина одного узла N - это глубина того запроса SELECT, которому принадлежит N.
|
|
|
|
|
* Дальше глубина одного запроса SELECT определяется следующим образом:
|
|
|
|
|
* - если запрос Q корневой, то select_query_depth(Q) = 0
|
2015-09-18 13:36:10 +00:00
|
|
|
|
* - если запрос S является непосредственным подзапросом одного запроса R,
|
|
|
|
|
* то select_query_depth(S) = select_query_depth(R) + 1
|
|
|
|
|
*/
|
|
|
|
|
UInt32 select_query_depth = 0;
|
2014-07-03 22:39:13 +00:00
|
|
|
|
|
2013-02-11 11:22:15 +00:00
|
|
|
|
/** Строка с полным запросом.
|
|
|
|
|
* Этот указатель не дает ее удалить, пока range в нее ссылается.
|
|
|
|
|
*/
|
|
|
|
|
StringPtr query_string;
|
2011-08-28 02:22:23 +00:00
|
|
|
|
|
2014-12-17 15:26:24 +00:00
|
|
|
|
IAST() = default;
|
|
|
|
|
IAST(const StringRange range_) : range(range_) {}
|
|
|
|
|
virtual ~IAST() = default;
|
2011-09-25 03:37:09 +00:00
|
|
|
|
|
2015-05-03 09:13:08 +00:00
|
|
|
|
/** Получить каноническое имя столбца, если элемент является столбцом */
|
|
|
|
|
virtual String getColumnName() const { throw Exception("Trying to get name of not a column: " + getID(), ErrorCodes::NOT_A_COLUMN); }
|
2011-11-06 04:21:09 +00:00
|
|
|
|
|
2015-05-03 09:13:08 +00:00
|
|
|
|
/** Получить алиас, если он есть, или каноническое имя столбца, если его нет. */
|
2014-07-03 22:39:13 +00:00
|
|
|
|
virtual String getAliasOrColumnName() const { return getColumnName(); }
|
|
|
|
|
|
|
|
|
|
/** Получить алиас, если он есть, или пустую строку, если его нет, или если элемент не поддерживает алиасы. */
|
|
|
|
|
virtual String tryGetAlias() const { return String(); }
|
|
|
|
|
|
|
|
|
|
/** Установить алиас. */
|
|
|
|
|
virtual void setAlias(const String & to)
|
|
|
|
|
{
|
|
|
|
|
throw Exception("Can't set alias of " + getColumnName(), ErrorCodes::UNKNOWN_TYPE_OF_AST_NODE);
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-09 19:19:00 +00:00
|
|
|
|
/** Получить текст, который идентифицирует этот элемент. */
|
2012-12-27 16:23:12 +00:00
|
|
|
|
virtual String getID() const = 0;
|
2011-08-09 19:19:00 +00:00
|
|
|
|
|
2011-12-12 06:15:34 +00:00
|
|
|
|
/** Получить глубокую копию дерева. */
|
|
|
|
|
virtual SharedPtr<IAST> clone() const = 0;
|
|
|
|
|
|
2015-09-18 13:36:10 +00:00
|
|
|
|
/// Рекурсивно установить атрибуты в поддереве, корнем которого является текущий узел.
|
|
|
|
|
void setAttributes(Attributes attributes_)
|
2015-02-18 23:15:20 +00:00
|
|
|
|
{
|
2015-09-18 13:36:10 +00:00
|
|
|
|
attributes |= attributes_;
|
|
|
|
|
for (auto it : children)
|
|
|
|
|
it->setAttributes(attributes_);
|
2015-02-18 23:15:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-03 09:13:08 +00:00
|
|
|
|
/** Получить текст, который идентифицирует этот элемент и всё поддерево.
|
|
|
|
|
* Обычно он содержит идентификатор элемента и getTreeID от всех детей.
|
|
|
|
|
*/
|
|
|
|
|
String getTreeID() const
|
|
|
|
|
{
|
|
|
|
|
std::stringstream s;
|
|
|
|
|
s << getID();
|
|
|
|
|
|
|
|
|
|
if (!children.empty())
|
|
|
|
|
{
|
|
|
|
|
s << "(";
|
|
|
|
|
for (ASTs::const_iterator it = children.begin(); it != children.end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
if (it != children.begin())
|
|
|
|
|
s << ", ";
|
|
|
|
|
s << (*it)->getTreeID();
|
|
|
|
|
}
|
|
|
|
|
s << ")";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return s.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void dumpTree(std::ostream & ostr, size_t indent = 0) const
|
|
|
|
|
{
|
|
|
|
|
String indent_str(indent, '-');
|
|
|
|
|
ostr << indent_str << getID() << ", " << this << std::endl;
|
|
|
|
|
for (ASTs::const_iterator it = children.begin(); it != children.end(); ++it)
|
|
|
|
|
(*it)->dumpTree(ostr, indent + 1);
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-26 20:29:28 +00:00
|
|
|
|
/** Проверить глубину дерева.
|
|
|
|
|
* Если задано max_depth и глубина больше - кинуть исключение.
|
2014-02-12 12:51:54 +00:00
|
|
|
|
* Возвращает глубину дерева.
|
2012-12-26 20:29:28 +00:00
|
|
|
|
*/
|
|
|
|
|
size_t checkDepth(size_t max_depth) const
|
|
|
|
|
{
|
2014-02-12 12:51:54 +00:00
|
|
|
|
return checkDepthImpl(max_depth, 0);
|
2012-12-26 20:29:28 +00:00
|
|
|
|
}
|
2014-07-03 22:39:13 +00:00
|
|
|
|
|
2012-12-26 20:29:28 +00:00
|
|
|
|
/** То же самое для общего количества элементов дерева.
|
|
|
|
|
*/
|
|
|
|
|
size_t checkSize(size_t max_size) const
|
|
|
|
|
{
|
|
|
|
|
size_t res = 1;
|
2015-05-03 09:13:08 +00:00
|
|
|
|
for (ASTs::const_iterator it = children.begin(); it != children.end(); ++it)
|
|
|
|
|
res += (*it)->checkSize(max_size);
|
2012-12-26 20:29:28 +00:00
|
|
|
|
|
|
|
|
|
if (res > max_size)
|
2013-06-21 20:34:19 +00:00
|
|
|
|
throw Exception("AST is too big. Maximum: " + toString(max_size), ErrorCodes::TOO_BIG_AST);
|
2014-07-03 22:39:13 +00:00
|
|
|
|
|
2012-12-26 20:29:28 +00:00
|
|
|
|
return res;
|
|
|
|
|
}
|
2013-08-13 08:54:28 +00:00
|
|
|
|
|
|
|
|
|
/** Получить set из имен индентификаторов
|
2015-05-03 09:13:08 +00:00
|
|
|
|
*/
|
2013-08-13 08:54:28 +00:00
|
|
|
|
virtual void collectIdentifierNames(IdentifierNameSet & set) const
|
|
|
|
|
{
|
2015-05-03 09:13:08 +00:00
|
|
|
|
for (ASTs::const_iterator it = children.begin(); it != children.end(); ++it)
|
|
|
|
|
(*it)->collectIdentifierNames(set);
|
2013-08-13 08:54:28 +00:00
|
|
|
|
}
|
2014-02-12 12:51:54 +00:00
|
|
|
|
|
2015-08-05 21:38:31 +00:00
|
|
|
|
|
|
|
|
|
/// Преобразовать в строку.
|
|
|
|
|
|
|
|
|
|
/// Настройки формата.
|
|
|
|
|
struct FormatSettings
|
|
|
|
|
{
|
|
|
|
|
std::ostream & ostr;
|
|
|
|
|
bool hilite;
|
|
|
|
|
bool one_line;
|
|
|
|
|
|
|
|
|
|
char nl_or_ws;
|
|
|
|
|
|
|
|
|
|
FormatSettings(std::ostream & ostr_, bool hilite_, bool one_line_)
|
|
|
|
|
: ostr(ostr_), hilite(hilite_), one_line(one_line_)
|
|
|
|
|
{
|
|
|
|
|
nl_or_ws = one_line ? ' ' : '\n';
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2015-08-06 21:32:51 +00:00
|
|
|
|
/// Состояние. Например, может запоминаться множество узлов, которых мы уже обошли.
|
2015-08-05 21:38:31 +00:00
|
|
|
|
struct FormatState
|
|
|
|
|
{
|
2015-08-06 21:32:51 +00:00
|
|
|
|
/** Запрос SELECT, в котором найден алиас; идентификатор узла с таким алиасом.
|
|
|
|
|
* Нужно, чтобы когда узел встретился повторно, выводить только алиас.
|
|
|
|
|
*/
|
|
|
|
|
std::set<std::pair<const IAST *, std::string>> printed_asts_with_alias;
|
2015-08-05 21:38:31 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// Состояние, которое копируется при форматировании каждого узла. Например, уровень вложенности.
|
|
|
|
|
struct FormatStateStacked
|
|
|
|
|
{
|
2015-08-09 05:10:43 +00:00
|
|
|
|
UInt8 indent = 0;
|
2015-08-05 21:38:31 +00:00
|
|
|
|
bool need_parens = false;
|
2015-08-06 21:32:51 +00:00
|
|
|
|
const IAST * current_select = nullptr;
|
2015-08-05 21:38:31 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void format(const FormatSettings & settings) const
|
|
|
|
|
{
|
|
|
|
|
FormatState state;
|
|
|
|
|
formatImpl(settings, state, FormatStateStacked());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const
|
|
|
|
|
{
|
|
|
|
|
throw Exception("Unknown element in AST: " + getID()
|
|
|
|
|
+ ((range.first && (range.second > range.first))
|
|
|
|
|
? " '" + std::string(range.first, range.second - range.first) + "'"
|
|
|
|
|
: ""),
|
|
|
|
|
ErrorCodes::UNKNOWN_ELEMENT_IN_AST);
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-06 03:26:27 +00:00
|
|
|
|
void writeAlias(const String & name, std::ostream & s, bool hilite) const;
|
2015-08-05 21:38:31 +00:00
|
|
|
|
|
2015-08-06 21:32:51 +00:00
|
|
|
|
protected:
|
|
|
|
|
/// Для подсветки синтаксиса.
|
|
|
|
|
static const char * hilite_keyword;
|
|
|
|
|
static const char * hilite_identifier;
|
|
|
|
|
static const char * hilite_function;
|
|
|
|
|
static const char * hilite_operator;
|
|
|
|
|
static const char * hilite_alias;
|
|
|
|
|
static const char * hilite_none;
|
|
|
|
|
|
2014-02-12 12:51:54 +00:00
|
|
|
|
private:
|
|
|
|
|
size_t checkDepthImpl(size_t max_depth, size_t level) const
|
|
|
|
|
{
|
|
|
|
|
size_t res = level + 1;
|
2015-05-03 09:13:08 +00:00
|
|
|
|
for (ASTs::const_iterator it = children.begin(); it != children.end(); ++it)
|
2014-02-12 12:51:54 +00:00
|
|
|
|
{
|
|
|
|
|
if (level >= max_depth)
|
|
|
|
|
throw Exception("AST is too deep. Maximum: " + toString(max_depth), ErrorCodes::TOO_DEEP_AST);
|
2015-05-03 09:13:08 +00:00
|
|
|
|
res = std::max(res, (*it)->checkDepthImpl(max_depth, level + 1));
|
2014-02-12 12:51:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
2010-06-24 19:12:10 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2016-01-11 21:46:36 +00:00
|
|
|
|
using ASTPtr = SharedPtr<IAST>;
|
|
|
|
|
using ASTs = std::vector<ASTPtr>;
|
2010-06-24 19:12:10 +00:00
|
|
|
|
|
2015-08-05 21:38:31 +00:00
|
|
|
|
|
|
|
|
|
/// Квотировать идентификатор обратными кавычками, если это требуется.
|
|
|
|
|
String backQuoteIfNeed(const String & x);
|
|
|
|
|
|
|
|
|
|
|
2010-06-24 19:12:10 +00:00
|
|
|
|
}
|