mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-21 09:10:48 +00:00
dbms: more compact formatting of queries with aliases: development [#METR-17606].
This commit is contained in:
parent
63a272ab71
commit
4ab0052456
@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <DB/Parsers/IAST.h>
|
||||
#include <mysqlxx/Manip.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -98,5 +100,87 @@ public:
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
protected:
|
||||
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
|
||||
{
|
||||
frame.need_parens = false;
|
||||
|
||||
std::string indent_str = settings.one_line ? "" : std::string(4 * frame.indent, ' ');
|
||||
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << "ALTER TABLE " << (settings.hilite ? hilite_none : "");
|
||||
|
||||
if (!table.empty())
|
||||
{
|
||||
if (!database.empty())
|
||||
{
|
||||
settings.ostr << indent_str << database;
|
||||
settings.ostr << ".";
|
||||
}
|
||||
settings.ostr << indent_str << table;
|
||||
}
|
||||
settings.ostr << nl_or_ws;
|
||||
|
||||
for (size_t i = 0; i < parameters.size(); ++i)
|
||||
{
|
||||
const ASTAlterQuery::Parameters & p = parameters[i];
|
||||
|
||||
if (p.type == ASTAlterQuery::ADD_COLUMN)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << "ADD COLUMN " << (settings.hilite ? hilite_none : "");
|
||||
p.col_decl->formatImpl(settings, state, frame);
|
||||
|
||||
/// AFTER
|
||||
if (p.column)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << " AFTER " << (settings.hilite ? hilite_none : "");
|
||||
p.column->formatImpl(settings, state, frame);
|
||||
}
|
||||
}
|
||||
else if (p.type == ASTAlterQuery::DROP_COLUMN)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << "DROP COLUMN " << (settings.hilite ? hilite_none : "");
|
||||
p.column->formatImpl(settings, state, frame);
|
||||
}
|
||||
else if (p.type == ASTAlterQuery::MODIFY_COLUMN)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << "MODIFY COLUMN " << (settings.hilite ? hilite_none : "");
|
||||
p.col_decl->formatImpl(settings, state, frame);
|
||||
}
|
||||
else if (p.type == ASTAlterQuery::DROP_PARTITION)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << (p.detach ? "DETACH" : "DROP") << " PARTITION "
|
||||
<< (settings.hilite ? hilite_none : "");
|
||||
p.partition->formatImpl(settings, state, frame);
|
||||
}
|
||||
else if (p.type == ASTAlterQuery::ATTACH_PARTITION)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << "ATTACH " << (p.unreplicated ? "UNREPLICATED " : "")
|
||||
<< (p.part ? "PART " : "PARTITION ") << (settings.hilite ? hilite_none : "");
|
||||
p.partition->formatImpl(settings, state, frame);
|
||||
}
|
||||
else if (p.type == ASTAlterQuery::FETCH_PARTITION)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << "FETCH " << (p.unreplicated ? "UNREPLICATED " : "")
|
||||
<< "PARTITION " << (settings.hilite ? hilite_none : "");
|
||||
p.partition->formatImpl(settings, state, frame);
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "")
|
||||
<< " FROM " << (settings.hilite ? hilite_none : "") << mysqlxx::quote << p.from;
|
||||
}
|
||||
else if (p.type == ASTAlterQuery::FREEZE_PARTITION)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << "FREEZE PARTITION " << (settings.hilite ? hilite_none : "");
|
||||
p.partition->formatImpl(settings, state, frame);
|
||||
}
|
||||
else
|
||||
throw Exception("Unexpected type of ALTER", ErrorCodes::UNEXPECTED_AST_STRUCTURE);
|
||||
|
||||
std::string comma = (i < (parameters.size() -1) ) ? "," : "";
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << comma << (settings.hilite ? hilite_none : "");
|
||||
|
||||
settings.ostr << settings.nl_or_ws;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -16,6 +16,12 @@ public:
|
||||
String getID() const override { return "Asterisk"; }
|
||||
ASTPtr clone() const override { return new ASTAsterisk(*this); }
|
||||
String getColumnName() const override { return "*"; }
|
||||
|
||||
protected:
|
||||
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
|
||||
{
|
||||
settings.ostr << "*";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -19,6 +19,28 @@ struct ASTCheckQuery : public IAST
|
||||
|
||||
std::string database;
|
||||
std::string table;
|
||||
|
||||
protected:
|
||||
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
|
||||
{
|
||||
std::string nl_or_nothing = settings.one_line ? "" : "\n";
|
||||
|
||||
std::string indent_str = settings.one_line ? "" : std::string(4 * frame.indent, ' ');
|
||||
std::string nl_or_ws = settings.one_line ? " " : "\n";
|
||||
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << "CHECK TABLE " << (settings.hilite ? hilite_none : "");
|
||||
|
||||
if (!table.empty())
|
||||
{
|
||||
if (!database.empty())
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << database << (settings.hilite ? hilite_none : "");
|
||||
settings.ostr << ".";
|
||||
}
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << table << (settings.hilite ? hilite_none : "");
|
||||
}
|
||||
settings.ostr << nl_or_ws;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -40,6 +40,26 @@ public:
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
|
||||
{
|
||||
frame.need_parens = false;
|
||||
std::string indent_str = settings.one_line ? "" : std::string(4 * frame.indent, ' ');
|
||||
|
||||
settings.ostr << settings.nl_or_ws << indent_str << backQuoteIfNeed(name);
|
||||
if (type)
|
||||
{
|
||||
settings.ostr << ' ';
|
||||
type->formatImpl(settings, state, frame);
|
||||
}
|
||||
|
||||
if (default_expression)
|
||||
{
|
||||
settings.ostr << ' ' << (settings.hilite ? hilite_keyword : "") << default_specifier << (settings.hilite ? hilite_none : "") << ' ';
|
||||
default_expression->formatImpl(settings, state, frame);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -48,6 +48,73 @@ public:
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
|
||||
{
|
||||
frame.need_parens = false;
|
||||
|
||||
if (!database.empty() && table.empty())
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << (attach ? "ATTACH DATABASE " : "CREATE DATABASE ") << (if_not_exists ? "IF NOT EXISTS " : "") << (settings.hilite ? hilite_none : "")
|
||||
<< backQuoteIfNeed(database);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
std::string what = "TABLE";
|
||||
if (is_view)
|
||||
what = "VIEW";
|
||||
if (is_materialized_view)
|
||||
what = "MATERIALIZED VIEW";
|
||||
|
||||
settings.ostr
|
||||
<< (settings.hilite ? hilite_keyword : "")
|
||||
<< (attach ? "ATTACH " : "CREATE ")
|
||||
<< (is_temporary ? "TEMPORARY " : "")
|
||||
<< what
|
||||
<< " " << (if_not_exists ? "IF NOT EXISTS " : "")
|
||||
<< (settings.hilite ? hilite_none : "")
|
||||
<< (!database.empty() ? backQuoteIfNeed(database) + "." : "") << backQuoteIfNeed(table);
|
||||
}
|
||||
|
||||
if (!as_table.empty())
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " AS " << (settings.hilite ? hilite_none : "")
|
||||
<< (!as_database.empty() ? backQuoteIfNeed(as_database) + "." : "") << backQuoteIfNeed(as_table);
|
||||
}
|
||||
|
||||
if (columns)
|
||||
{
|
||||
settings.ostr << (settings.one_line ? " (" : "\n(");
|
||||
++frame.indent;
|
||||
columns->formatImpl(settings, state, frame);
|
||||
settings.ostr << (settings.one_line ? ")" : "\n)");
|
||||
}
|
||||
|
||||
if (storage && !is_materialized_view && !is_view)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " ENGINE" << (settings.hilite ? hilite_none : "") << " = ";
|
||||
storage->formatImpl(settings, state, frame);
|
||||
}
|
||||
|
||||
if (inner_storage)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " ENGINE" << (settings.hilite ? hilite_none : "") << " = ";
|
||||
inner_storage->formatImpl(settings, state, frame);
|
||||
}
|
||||
|
||||
if (is_populate)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " POPULATE" << (settings.hilite ? hilite_none : "");
|
||||
}
|
||||
|
||||
if (select)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " AS" << settings.nl_or_ws << (settings.hilite ? hilite_none : "");
|
||||
select->formatImpl(settings, state, frame);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -24,6 +24,25 @@ public:
|
||||
String getID() const override { return (detach ? "DetachQuery_" : "DropQuery_") + database + "_" + table; };
|
||||
|
||||
ASTPtr clone() const override { return new ASTDropQuery(*this); }
|
||||
|
||||
protected:
|
||||
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
|
||||
{
|
||||
if (table.empty() && !database.empty())
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "")
|
||||
<< (detach ? "DETACH DATABASE " : "DROP DATABASE ")
|
||||
<< (if_exists ? "IF EXISTS " : "")
|
||||
<< (settings.hilite ? hilite_none : "")
|
||||
<< backQuoteIfNeed(database);
|
||||
return;
|
||||
}
|
||||
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "")
|
||||
<< (detach ? "DETACH TABLE " : "DROP TABLE ")
|
||||
<< (if_exists ? "IF EXISTS " : "") << (settings.hilite ? hilite_none : "")
|
||||
<< (!database.empty() ? backQuoteIfNeed(database) + "." : "") << backQuoteIfNeed(table);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -31,6 +31,40 @@ public:
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
|
||||
{
|
||||
for (ASTs::const_iterator it = children.begin(); it != children.end(); ++it)
|
||||
{
|
||||
if (it != children.begin())
|
||||
settings.ostr << ", ";
|
||||
|
||||
(*it)->formatImpl(settings, state, frame);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
friend class ASTSelectQuery;
|
||||
|
||||
/** Вывести список выражений в секциях запроса SELECT - по одному выражению на строку.
|
||||
*/
|
||||
void formatImplMultiline(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const
|
||||
{
|
||||
std::string indent_str = "\n" + std::string(4 * (frame.indent + 1), ' ');
|
||||
|
||||
++frame.indent;
|
||||
for (ASTs::const_iterator it = children.begin(); it != children.end(); ++it)
|
||||
{
|
||||
if (it != children.begin())
|
||||
settings.ostr << ", ";
|
||||
|
||||
if (children.size() > 1)
|
||||
settings.ostr << indent_str;
|
||||
|
||||
(*it)->formatImpl(settings, state, frame);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -82,6 +82,9 @@ public:
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override;
|
||||
};
|
||||
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <DB/DataTypes/IDataType.h>
|
||||
#include <DB/Parsers/ASTWithAlias.h>
|
||||
#include <DB/IO/WriteBufferFromOStream.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -41,6 +42,28 @@ public:
|
||||
{
|
||||
set.insert(name);
|
||||
}
|
||||
|
||||
protected:
|
||||
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
|
||||
{
|
||||
if (frame.need_parens && !alias.empty())
|
||||
settings.ostr << '(';
|
||||
|
||||
settings.ostr << (settings.hilite ? hilite_identifier : "");
|
||||
|
||||
WriteBufferFromOStream wb(settings.ostr, 32);
|
||||
writeProbablyBackQuotedString(name, wb);
|
||||
wb.next();
|
||||
|
||||
settings.ostr << (settings.hilite ? hilite_none : "");
|
||||
|
||||
if (!alias.empty())
|
||||
{
|
||||
writeAlias(alias, settings.ostr, settings.hilite);
|
||||
if (frame.need_parens)
|
||||
settings.ostr << ')';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -42,6 +42,43 @@ public:
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
|
||||
{
|
||||
frame.need_parens = false;
|
||||
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << "INSERT INTO " << (settings.hilite ? hilite_none : "")
|
||||
<< (!database.empty() ? backQuoteIfNeed(database) + "." : "") << backQuoteIfNeed(table);
|
||||
|
||||
if (!insert_id.empty())
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " ID = " << (settings.hilite ? hilite_none : "")
|
||||
<< mysqlxx::quote << insert_id;
|
||||
|
||||
if (columns)
|
||||
{
|
||||
settings.ostr << " (";
|
||||
columns->formatImpl(settings, state, frame);
|
||||
settings.ostr << ")";
|
||||
}
|
||||
|
||||
if (select)
|
||||
{
|
||||
settings.ostr << " ";
|
||||
select->formatImpl(settings, state, frame);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!format.empty())
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " FORMAT " << (settings.hilite ? hilite_none : "") << format;
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " VALUES" << (settings.hilite ? hilite_none : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -83,6 +83,37 @@ public:
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
|
||||
{
|
||||
frame.need_parens = false;
|
||||
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "");
|
||||
|
||||
if (locality == ASTJoin::Global)
|
||||
settings.ostr << "GLOBAL ";
|
||||
|
||||
if (kind != ASTJoin::Cross)
|
||||
settings.ostr << (strictness == ASTJoin::Any ? "ANY " : "ALL ");
|
||||
|
||||
settings.ostr << (kind == ASTJoin::Inner ? "INNER "
|
||||
: (kind == ASTJoin::Left ? "LEFT "
|
||||
: (kind == ASTJoin::Right ? "RIGHT "
|
||||
: (kind == ASTJoin::Cross ? "CROSS "
|
||||
: "FULL OUTER "))));
|
||||
|
||||
settings.ostr << "JOIN "
|
||||
<< (settings.hilite ? hilite_none : "");
|
||||
|
||||
table->formatImpl(settings, state, frame);
|
||||
|
||||
if (kind != ASTJoin::Cross)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " USING " << (settings.hilite ? hilite_none : "");
|
||||
using_expr_list->formatImpl(settings, state, frame);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -26,6 +26,22 @@ public:
|
||||
String getID() const override { return "Literal_" + apply_visitor(FieldVisitorDump(), value); }
|
||||
|
||||
ASTPtr clone() const override { return new ASTLiteral(*this); }
|
||||
|
||||
protected:
|
||||
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
|
||||
{
|
||||
if (frame.need_parens && !alias.empty())
|
||||
settings.ostr <<'(';
|
||||
|
||||
settings.ostr <<apply_visitor(FieldVisitorToString(), value);
|
||||
|
||||
if (!alias.empty())
|
||||
{
|
||||
writeAlias(alias, settings.ostr, settings.hilite);
|
||||
if (frame.need_parens)
|
||||
settings.ostr <<')';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -34,6 +34,15 @@ public:
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
|
||||
{
|
||||
std::string indent_str = settings.one_line ? "" : std::string(4 * frame.indent, ' ');
|
||||
|
||||
s << settings.nl_or_ws << indent_str << backQuoteIfNeed(name) << " ";
|
||||
type->formatImpl(settings, state, frame);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -22,6 +22,13 @@ public:
|
||||
String getID() const override { return "OptimizeQuery_" + database + "_" + table; };
|
||||
|
||||
ASTPtr clone() const override { return new ASTOptimizeQuery(*this); }
|
||||
|
||||
protected:
|
||||
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << "OPTIMIZE TABLE " << (settings.hilite ? hilite_none : "")
|
||||
<< (!database.empty() ? backQuoteIfNeed(database) + "." : "") << backQuoteIfNeed(table);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -29,6 +29,18 @@ public:
|
||||
String getID() const override { return "OrderByElement"; }
|
||||
|
||||
ASTPtr clone() const override { return new ASTOrderByElement(*this); }
|
||||
|
||||
protected:
|
||||
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
|
||||
{
|
||||
children.front()->formatImpl(settings, state, frame);
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << (direction == -1 ? " DESC" : " ASC") << (settings.hilite ? hilite_none : "");
|
||||
if (!collator.isNull())
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " COLLATE " << (settings.hilite ? hilite_none : "")
|
||||
<< "'" << collator->getLocale() << "'";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -8,17 +8,17 @@ namespace DB
|
||||
{
|
||||
|
||||
|
||||
/** Запрос с указанием названия таблицы и, возможно, БД и секцией FORMAT.
|
||||
*/
|
||||
class ASTQueryWithTableAndOutput : public ASTQueryWithOutput
|
||||
{
|
||||
public:
|
||||
String database;
|
||||
String table;
|
||||
|
||||
ASTQueryWithTableAndOutput() = default;
|
||||
ASTQueryWithTableAndOutput(const StringRange range_) : ASTQueryWithOutput(range_) {}
|
||||
};
|
||||
/** Запрос с указанием названия таблицы и, возможно, БД и секцией FORMAT.
|
||||
*/
|
||||
class ASTQueryWithTableAndOutput : public ASTQueryWithOutput
|
||||
{
|
||||
public:
|
||||
String database;
|
||||
String table;
|
||||
|
||||
ASTQueryWithTableAndOutput() = default;
|
||||
ASTQueryWithTableAndOutput(const StringRange range_) : ASTQueryWithOutput(range_) {}
|
||||
};
|
||||
|
||||
|
||||
/// Объявляет класс-наследник ASTQueryWithTableAndOutput с реализованными методами getID и clone.
|
||||
|
@ -34,6 +34,22 @@ public:
|
||||
String getID() const override { return "Rename"; };
|
||||
|
||||
ASTPtr clone() const override { return new ASTRenameQuery(*this); }
|
||||
|
||||
protected:
|
||||
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << "RENAME TABLE " << (settings.hilite ? hilite_none : "");
|
||||
|
||||
for (ASTRenameQuery::Elements::const_iterator it = elements.begin(); it != elements.end(); ++it)
|
||||
{
|
||||
if (it != elements.begin())
|
||||
settings.ostr << ", ";
|
||||
|
||||
settings.ostr << (!it->from.database.empty() ? backQuoteIfNeed(it->from.database) + "." : "") << backQuoteIfNeed(it->from.table)
|
||||
<< (settings.hilite ? hilite_keyword : "") << " TO " << (settings.hilite ? hilite_none : "")
|
||||
<< (!it->to.database.empty() ? backQuoteIfNeed(it->to.database) + "." : "") << backQuoteIfNeed(it->to.table);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -68,6 +68,9 @@ public:
|
||||
ASTPtr prev_union_all;
|
||||
/// Следующий запрос SELECT в цепочке UNION ALL, если такой есть
|
||||
ASTPtr next_union_all;
|
||||
|
||||
protected:
|
||||
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -133,6 +133,65 @@ public:
|
||||
(*it)->collectIdentifierNames(set);
|
||||
}
|
||||
|
||||
|
||||
/// Преобразовать в строку.
|
||||
|
||||
/// Настройки формата.
|
||||
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';
|
||||
}
|
||||
};
|
||||
|
||||
/// Состояние. Например, множество узлов DAG, которых мы уже обошли.
|
||||
struct FormatState
|
||||
{
|
||||
/// TODO
|
||||
};
|
||||
|
||||
/// Состояние, которое копируется при форматировании каждого узла. Например, уровень вложенности.
|
||||
struct FormatStateStacked
|
||||
{
|
||||
bool indent = 0;
|
||||
bool need_parens = false;
|
||||
};
|
||||
|
||||
void format(const FormatSettings & settings) const
|
||||
{
|
||||
FormatState state;
|
||||
formatImpl(settings, state, FormatStateStacked());
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void writeAlias(const String & name, std::ostream & s, bool hilite);
|
||||
|
||||
private:
|
||||
size_t checkDepthImpl(size_t max_depth, size_t level) const
|
||||
{
|
||||
@ -152,4 +211,9 @@ private:
|
||||
typedef SharedPtr<IAST> ASTPtr;
|
||||
typedef std::vector<ASTPtr> ASTs;
|
||||
|
||||
|
||||
/// Квотировать идентификатор обратными кавычками, если это требуется.
|
||||
String backQuoteIfNeed(const String & x);
|
||||
|
||||
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ namespace DB
|
||||
/** Берёт синтаксическое дерево и превращает его обратно в текст.
|
||||
* В случае запроса INSERT, данные будут отсутствовать.
|
||||
*/
|
||||
void formatAST(const IAST & ast, std::ostream & s, size_t indent = 0, bool hilite = true, bool one_line = false, bool need_parens = false);
|
||||
void formatAST(const IAST & ast, std::ostream & s, size_t indent = 0, bool hilite = true, bool one_line = false, bool need_parens = false);
|
||||
|
||||
|
||||
String formatColumnsForCreateQuery(NamesAndTypesList & columns);
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include <DB/Parsers/ASTSetQuery.h>
|
||||
#include <DB/Parsers/ASTSelectQuery.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
@ -217,5 +219,151 @@ const IAST * ASTSelectQuery::getFormat() const
|
||||
return query->format.get();
|
||||
}
|
||||
|
||||
|
||||
void ASTSelectQuery::formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
|
||||
{
|
||||
frame.need_parens = false;
|
||||
std::string indent_str = settings.one_line ? "" : std::string(4 * frame.indent, ' ');
|
||||
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str << "SELECT " << (distinct ? "DISTINCT " : "") << (settings.hilite ? hilite_none : "");
|
||||
|
||||
settings.one_line
|
||||
? select_expression_list->formatImpl(settings, state, frame)
|
||||
: typeid_cast<const ASTExpressionList &>(*select_expression_list).formatImplMultiline(settings, state, frame);
|
||||
|
||||
if (table)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << settings.nl_or_ws << settings.ostr << indent_str << "FROM " << (settings.hilite ? hilite_none : "");
|
||||
if (database)
|
||||
{
|
||||
database->formatImpl(settings, state, frame);
|
||||
settings.ostr << ".";
|
||||
}
|
||||
|
||||
if (typeid_cast<const ASTSelectQuery *>(&*table))
|
||||
{
|
||||
if (settings.one_line)
|
||||
settings.ostr << " (";
|
||||
else
|
||||
settings.ostr << "\n" << indent_str << "(\n";
|
||||
|
||||
table->formatImpl(settings, state, frame);
|
||||
|
||||
if (settings.one_line)
|
||||
settings.ostr << ")";
|
||||
else
|
||||
settings.ostr << "\n" << indent_str << ")";
|
||||
}
|
||||
else
|
||||
table->formatImpl(settings, state, frame);
|
||||
}
|
||||
|
||||
if (final)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << settings.nl_or_ws << settings.ostr << indent_str << "FINAL" << (settings.hilite ? hilite_none : "");
|
||||
}
|
||||
|
||||
if (sample_size)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << settings.nl_or_ws << settings.ostr << indent_str << "SAMPLE " << (settings.hilite ? hilite_none : "");
|
||||
sample_size->formatImpl(settings, state, frame);
|
||||
}
|
||||
|
||||
if (array_join_expression_list)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << settings.nl_or_ws << settings.ostr << indent_str
|
||||
<< (array_join_is_left ? "LEFT " : "") << "ARRAY JOIN " << (settings.hilite ? hilite_none : "");
|
||||
|
||||
settings.one_line
|
||||
? array_join_expression_list->formatImpl(settings, state, frame)
|
||||
: typeid_cast<const ASTExpressionList &>(*array_join_expression_list).formatImplMultiline(settings, state, frame);
|
||||
}
|
||||
|
||||
if (join)
|
||||
{
|
||||
settings.ostr << " ";
|
||||
join->formatImpl(settings, state, frame);
|
||||
}
|
||||
|
||||
if (prewhere_expression)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << settings.nl_or_ws << settings.ostr << indent_str << "PREWHERE " << (settings.hilite ? hilite_none : "");
|
||||
prewhere_expression->formatImpl(settings, state, frame);
|
||||
}
|
||||
|
||||
if (where_expression)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << settings.nl_or_ws << settings.ostr << indent_str << "WHERE " << (settings.hilite ? hilite_none : "");
|
||||
where_expression, s, indent, hilite, settings.one_line);
|
||||
}
|
||||
|
||||
if (group_expression_list)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << settings.nl_or_ws << settings.ostr << indent_str << "GROUP BY " << (settings.hilite ? hilite_none : "");
|
||||
settings.one_line
|
||||
? group_expression_list->formatImpl(settings, state, frame)
|
||||
: typeid_cast<const ASTExpressionList &>(*group_expression_list).formatImplMultiline(settings, state, frame);
|
||||
}
|
||||
|
||||
if (group_by_with_totals)
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << settings.nl_or_ws << settings.ostr << indent_str << (settings.one_line ? "" : " ") << "WITH TOTALS" << (settings.hilite ? hilite_none : "");
|
||||
|
||||
if (having_expression)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << settings.nl_or_ws << settings.ostr << indent_str << "HAVING " << (settings.hilite ? hilite_none : "");
|
||||
having_expression->formatImpl(settings, state, frame);
|
||||
}
|
||||
|
||||
if (order_expression_list)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << settings.nl_or_ws << settings.ostr << indent_str << "ORDER BY " << (settings.hilite ? hilite_none : "");
|
||||
settings.one_line
|
||||
? order_expression_list->formatImpl(settings, state, frame)
|
||||
: typeid_cast<const ASTExpressionList &>(*order_expression_list).formatImplMultiline(settings, state, frame);
|
||||
}
|
||||
|
||||
if (limit_length)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << settings.nl_or_ws << settings.ostr << indent_str << "LIMIT " << (settings.hilite ? hilite_none : "");
|
||||
if (limit_offset)
|
||||
{
|
||||
limit_offset->formatImpl(settings, state, frame);
|
||||
settings.ostr << ", ";
|
||||
}
|
||||
limit_length->formatImpl(settings, state, frame);
|
||||
}
|
||||
|
||||
if (settings)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << settings.nl_or_ws << settings.ostr << indent_str << "SETTINGS " << (settings.hilite ? hilite_none : "");
|
||||
|
||||
const ASTSetQuery & ast_set = typeid_cast<const ASTSetQuery &>(*settings);
|
||||
for (ASTSetQuery::Changes::const_iterator it = ast_set.changes.begin(); it != ast_set.changes.end(); ++it)
|
||||
{
|
||||
if (it != ast_set.changes.begin())
|
||||
settings.ostr << ", ";
|
||||
|
||||
settings.ostr << it->name << " = " << apply_visitor(FieldVisitorToString(), it->value);
|
||||
}
|
||||
}
|
||||
|
||||
if (format)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << settings.nl_or_ws << settings.ostr << indent_str << "FORMAT " << (settings.hilite ? hilite_none : "");
|
||||
format->formatImpl(settings, state, frame);
|
||||
}
|
||||
|
||||
if (next_union_all)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << settings.nl_or_ws << settings.ostr << indent_str << "UNION ALL " << settings.nl_or_ws << settings.ostr << (settings.hilite ? hilite_none : "");
|
||||
|
||||
// NOTE Мы можем безопасно применить static_cast вместо typeid_cast, потому что знаем, что в цепочке UNION ALL
|
||||
// имеются только деревья типа SELECT.
|
||||
const ASTSelectQuery & next_ast = static_cast<const ASTSelectQuery &>(*next_union_all);
|
||||
|
||||
next_ast->formatImpl(settings, state, frame);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
@ -63,7 +63,7 @@ String backQuoteIfNeed(const String & x)
|
||||
}
|
||||
|
||||
|
||||
static String hightlight(const String & keyword, const String & color_sequence, const bool hilite)
|
||||
static String highlight(const String & keyword, const String & color_sequence, const bool hilite)
|
||||
{
|
||||
return hilite ? color_sequence + keyword + hilite_none : keyword;
|
||||
}
|
||||
@ -81,6 +81,21 @@ static void writeAlias(const String & name, std::ostream & s, bool hilite, bool
|
||||
}
|
||||
|
||||
|
||||
struct FormatState
|
||||
{
|
||||
std::ostream & s;
|
||||
bool hilite;
|
||||
bool one_line;
|
||||
|
||||
void formatImpl(const IAST & ast, size_t indent, bool need_parens);
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void formatAST(const ASTExpressionList & ast, std::ostream & s, size_t indent, bool hilite, bool one_line, bool need_parens)
|
||||
{
|
||||
for (ASTs::const_iterator it = ast.children.begin(); it != ast.children.end(); ++it)
|
||||
@ -729,7 +744,7 @@ void formatAST(const ASTColumnDeclaration & ast, std::ostream & s, size_t indent
|
||||
|
||||
if (ast.default_expression)
|
||||
{
|
||||
s << ' ' << hightlight(ast.default_specifier, hilite_keyword, hilite) << ' ';
|
||||
s << ' ' << highlight(ast.default_specifier, hilite_keyword, hilite) << ' ';
|
||||
formatAST(*ast.default_expression, s, indent, hilite, one_line);
|
||||
}
|
||||
}
|
||||
@ -908,10 +923,16 @@ void formatAST(const ASTMultiQuery & ast, std::ostream & s, size_t indent, bool
|
||||
|
||||
void formatAST(const IAST & ast, std::ostream & s, size_t indent, bool hilite, bool one_line, bool need_parens)
|
||||
{
|
||||
FormatState state = { .s = s, .hilite = hilite, .one_line = one_line };
|
||||
state.formatImpl(ast, indent, need_parens);
|
||||
}
|
||||
|
||||
|
||||
void FormatState::formatImpl(const IAST & ast, size_t indent, bool need_parens)
|
||||
{
|
||||
#define DISPATCH(NAME) \
|
||||
else if (const AST ## NAME * concrete = typeid_cast<const AST ## NAME *>(&ast)) \
|
||||
formatAST(*concrete, s, indent, hilite, one_line, need_parens);
|
||||
state.formatImpl(*concrete, indent, need_parens);
|
||||
|
||||
if (false) {}
|
||||
DISPATCH(SelectQuery)
|
||||
|
Loading…
Reference in New Issue
Block a user