dbms: better handling of compound identifiers [#METR-18692].

This commit is contained in:
Alexey Milovidov 2015-11-08 04:29:37 +03:00
parent 4482871274
commit 0e5bf428d0
3 changed files with 60 additions and 47 deletions

View File

@ -21,7 +21,7 @@ public:
Format,
};
/// имя
/// имя. У составного идентификатора здесь будет конкатенированное имя (вида a.b.c), а отдельные составляюшие будут доступны внутри children.
String name;
/// чего идентифицирует этот идентификатор
@ -44,16 +44,7 @@ public:
}
protected:
void formatImplWithoutAlias(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
{
settings.ostr << (settings.hilite ? hilite_identifier : "");
WriteBufferFromOStream wb(settings.ostr, 32);
writeProbablyBackQuotedString(name, wb);
wb.next();
settings.ostr << (settings.hilite ? hilite_none : "");
}
void formatImplWithoutAlias(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override;
};
}

View File

@ -0,0 +1,38 @@
#include <DB/Parsers/ASTIdentifier.h>
namespace DB
{
void ASTIdentifier::formatImplWithoutAlias(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const
{
auto format_element = [&](const String & name)
{
settings.ostr << (settings.hilite ? hilite_identifier : "");
WriteBufferFromOStream wb(settings.ostr, 32);
writeProbablyBackQuotedString(name, wb);
wb.next();
settings.ostr << (settings.hilite ? hilite_none : "");
};
/// Простой или составной идентификатор?
if (children.size() > 1)
{
for (size_t i = 0, size = children.size(); i < size; ++i)
{
if (i != 0)
settings.ostr << '.';
format_element(static_cast<const ASTIdentifier &>(*children[i].get()).name);
}
}
else
{
format_element(name);
}
}
}

View File

@ -18,6 +18,7 @@
#include <DB/Parsers/ParserSelectQuery.h>
#include <DB/Parsers/ExpressionElementParsers.h>
#include <DB/Parsers/formatAST.h>
namespace DB
@ -165,44 +166,27 @@ bool ParserCompoundIdentifier::parseImpl(Pos & pos, Pos end, ASTPtr & node, Pos
{
Pos begin = pos;
/// Идентификатор в обратных кавычках
if (pos != end && *pos == '`')
{
ReadBuffer buf(const_cast<char *>(pos), end - pos, 0);
String s;
readBackQuotedString(s, buf);
pos += buf.count();
node = new ASTIdentifier(StringRange(begin, pos), s);
return true;
}
else
{
while (pos != end)
{
while (pos != end
&& ((*pos >= 'a' && *pos <= 'z')
|| (*pos >= 'A' && *pos <= 'Z')
|| (*pos == '_')
|| (pos != begin && *pos >= '0' && *pos <= '9')))
++pos;
ASTPtr id_list;
if (!ParserList(ParserPtr(new ParserIdentifier), ParserPtr(new ParserString(".")), false)
.parse(pos, end, id_list, max_parsed_pos, expected))
return false;
/// Если следующий символ - точка '.' и за ней следует, не цифра,
/// то продолжаем парсинг имени идентификатора
if (pos != begin && pos + 1 < end && *pos == '.' &&
!(*(pos + 1) >= '0' && *(pos + 1) <= '9'))
++pos;
else
break;
}
if (pos != begin)
{
node = new ASTIdentifier(StringRange(begin, pos), String(begin, pos - begin));
return true;
}
else
return false;
String name;
const ASTExpressionList & list = static_cast<const ASTExpressionList &>(*id_list.get());
for (const auto & child : list.children)
{
if (!name.empty())
name += '.';
name += static_cast<const ASTIdentifier &>(*child.get()).name;
}
node = new ASTIdentifier(StringRange(begin, pos), name);
/// В children запомним идентификаторы-составляющие, если их больше одного.
if (list.children.size() > 1)
node->children.insert(node->children.end(), list.children.begin(), list.children.end());
return true;
}