added former WITH clause to SELECT query

This commit is contained in:
Nikolai Kochetov 2017-08-10 17:46:46 +03:00 committed by alexey-milovidov
parent 9b99dfb53d
commit 37b6c98752
16 changed files with 60 additions and 23 deletions

View File

@ -1228,6 +1228,7 @@ static ASTPtr addTypeConversion(std::unique_ptr<ASTLiteral> && ast, const String
auto func = std::make_shared<ASTFunction>(ast->range);
ASTPtr res = func;
func->alias = ast->alias;
func->prefer_alias_to_column_name = ast->prefer_alias_to_column_name;
ast->alias.clear();
func->kind = ASTFunction::FUNCTION;
func->name = "CAST";
@ -1300,6 +1301,7 @@ void ExpressionAnalyzer::executeScalarSubqueriesImpl(ASTPtr & ast)
{
auto lit = std::make_unique<ASTLiteral>(ast->range, (*block.safeGetByPosition(0).column)[0]);
lit->alias = subquery->alias;
lit->prefer_alias_to_column_name = subquery->prefer_alias_to_column_name;
ast = addTypeConversion(std::move(lit), block.safeGetByPosition(0).type->getName());
}
else

View File

@ -1,6 +1,7 @@
#include <Common/typeid_cast.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/ASTWithAlias.h>
#include <IO/WriteHelpers.h>
#include <IO/WriteBufferFromString.h>
@ -8,7 +9,7 @@
namespace DB
{
String ASTFunction::getColumnName() const
String ASTFunction::getColumnNameImpl() const
{
WriteBufferFromOwnString wb;
writeString(name, wb);

View File

@ -34,8 +34,6 @@ public:
ASTFunction() = default;
ASTFunction(const StringRange range_) : ASTWithAlias(range_) {}
String getColumnName() const override;
/** Get text identifying the AST node. */
String getID() const override;
@ -43,6 +41,7 @@ public:
protected:
void formatImplWithoutAlias(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override;
String getColumnNameImpl() const override;
};

View File

@ -29,8 +29,6 @@ public:
ASTIdentifier(const StringRange range_, const String & name_, const Kind kind_ = Column)
: ASTWithAlias(range_), name(name_), kind(kind_) {}
String getColumnName() const override { return name; }
/** Get the text that identifies this element. */
String getID() const override { return "Identifier_" + name; }
@ -43,6 +41,7 @@ public:
protected:
void formatImplWithoutAlias(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override;
String getColumnNameImpl() const override { return name; }
};
}

View File

@ -8,7 +8,7 @@ namespace DB
{
String ASTLiteral::getColumnName() const
String ASTLiteral::getColumnNameImpl() const
{
/// Special case for very large arrays. Instead of listing all elements, will use hash of them.
/// (Otherwise column name will be too long, that will lead to significant slowdown of expression analysis.)

View File

@ -18,8 +18,6 @@ public:
ASTLiteral() = default;
ASTLiteral(const StringRange range_, const Field & value_) : ASTWithAlias(range_), value(value_) {}
String getColumnName() const override;
/** Get the text that identifies this element. */
String getID() const override { return "Literal_" + applyVisitor(FieldVisitorDump(), value); }
@ -30,6 +28,7 @@ protected:
{
settings.ostr << applyVisitor(FieldVisitorToString(), value);
}
String getColumnNameImpl() const override;
};
}

View File

@ -197,6 +197,7 @@ std::shared_ptr<ASTSelectQuery> ASTSelectQuery::cloneImpl(bool traverse_union_al
* And if the cloning order does not match the parsing order,
* then different servers will get different identifiers.
*/
CLONE(with_expression_list)
CLONE(select_expression_list)
CLONE(tables)
CLONE(prewhere_expression)
@ -232,6 +233,15 @@ void ASTSelectQuery::formatQueryImpl(const FormatSettings & s, FormatState & sta
frame.need_parens = false;
std::string indent_str = s.one_line ? "" : std::string(4 * frame.indent, ' ');
if (with_expression_list)
{
s.ostr << (s.hilite ? hilite_keyword : "") << indent_str << "WITH " << (s.hilite ? hilite_none : "");
s.one_line
? with_expression_list->formatImpl(s, state, frame)
: typeid_cast<const ASTExpressionList &>(*with_expression_list).formatImplMultiline(s, state, frame);
s.ostr << s.nl_or_ws;
}
s.ostr << (s.hilite ? hilite_keyword : "") << indent_str << "SELECT " << (distinct ? "DISTINCT " : "") << (s.hilite ? hilite_none : "");
s.one_line

View File

@ -46,6 +46,7 @@ private:
public:
bool distinct = false;
ASTPtr with_expression_list;
ASTPtr select_expression_list;
ASTPtr tables;
ASTPtr prewhere_expression;

View File

@ -3,7 +3,7 @@
namespace DB
{
String ASTSubquery::getColumnName() const
String ASTSubquery::getColumnNameImpl() const
{
/// This is a hack. We use alias, if available, because otherwise tree could change during analysis.
return alias.empty() ? getTreeID() : alias;

View File

@ -31,8 +31,6 @@ public:
return ptr;
}
String getColumnName() const override;
protected:
void formatImplWithoutAlias(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override
{
@ -46,6 +44,7 @@ protected:
children[0]->formatImpl(settings, state, frame_nested);
settings.ostr << nl_or_nothing << indent_str << ")";
}
String getColumnNameImpl() const override;
};
}

View File

@ -14,10 +14,14 @@ class ASTWithAlias : public IAST
public:
/// The alias, if any, or an empty string.
String alias;
/// If is true, getColumnName returns alias. Uses for aliases in former WITH section of SELECT query.
/// Example: 'WITH pow(2, 2) as a SELECT pow(a, 2)' returns 'pow(a, 2)' instead of 'pow(pow(2, 2), 2)'
bool prefer_alias_to_column_name = false;
using IAST::IAST;
String getAliasOrColumnName() const override { return alias.empty() ? getColumnName() : alias; }
String getColumnName() const override final { return prefer_alias_to_column_name && !alias.empty() ? alias : getColumnNameImpl(); }
String getAliasOrColumnName() const override { return alias.empty() ? getColumnNameImpl() : alias; }
String tryGetAlias() const override { return alias; }
void setAlias(const String & to) override { alias = to; }
@ -25,6 +29,9 @@ public:
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override final;
virtual void formatImplWithoutAlias(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const = 0;
protected:
virtual String getColumnNameImpl() const = 0;
};
/// helper for setting aliases and chaining result to other functions

View File

@ -767,7 +767,10 @@ bool ParserWithOptionalAliasImpl<ParserAlias>::parseImpl(Pos & pos, ASTPtr & nod
String alias_name = typeid_cast<ASTIdentifier &>(*alias_node).name;
if (ASTWithAlias * ast_with_alias = dynamic_cast<ASTWithAlias *>(node.get()))
{
ast_with_alias->alias = alias_name;
ast_with_alias->prefer_alias_to_column_name = prefer_alias_to_column_name;
}
else
{
expected.add(pos, "alias cannot be here");

View File

@ -209,11 +209,13 @@ template <typename ParserAlias>
class ParserWithOptionalAliasImpl : public IParserBase
{
public:
ParserWithOptionalAliasImpl(ParserPtr && elem_parser_, bool allow_alias_without_as_keyword_)
: elem_parser(std::move(elem_parser_)), allow_alias_without_as_keyword(allow_alias_without_as_keyword_) {}
ParserWithOptionalAliasImpl(ParserPtr && elem_parser_, bool allow_alias_without_as_keyword_, bool prefer_alias_to_column_name_ = false)
: elem_parser(std::move(elem_parser_)), allow_alias_without_as_keyword(allow_alias_without_as_keyword_),
prefer_alias_to_column_name(prefer_alias_to_column_name_) {}
protected:
ParserPtr elem_parser;
bool allow_alias_without_as_keyword;
bool prefer_alias_to_column_name;
const char * getName() const { return "element of expression with optional alias"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected);

View File

@ -532,14 +532,16 @@ bool ParserTupleElementExpression::parseImpl(Pos & pos, ASTPtr & node, Expected
}
ParserExpressionWithOptionalAlias::ParserExpressionWithOptionalAlias(bool allow_alias_without_as_keyword)
: impl(std::make_unique<ParserWithOptionalAlias>(std::make_unique<ParserExpression>(), allow_alias_without_as_keyword))
ParserExpressionWithOptionalAlias::ParserExpressionWithOptionalAlias(bool allow_alias_without_as_keyword, bool prefer_alias_to_column_name)
: impl(std::make_unique<ParserWithOptionalAlias>(std::make_unique<ParserExpression>(),
allow_alias_without_as_keyword, prefer_alias_to_column_name))
{
}
ParserExpressionInCastExpression::ParserExpressionInCastExpression(bool allow_alias_without_as_keyword)
: impl(std::make_unique<ParserCastExpressionWithOptionalAlias>(std::make_unique<ParserExpression>(), allow_alias_without_as_keyword))
: impl(std::make_unique<ParserCastExpressionWithOptionalAlias>(std::make_unique<ParserExpression>(),
allow_alias_without_as_keyword, false))
{
}
@ -547,7 +549,7 @@ ParserExpressionInCastExpression::ParserExpressionInCastExpression(bool allow_al
bool ParserExpressionList::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
return ParserList(
std::make_unique<ParserExpressionWithOptionalAlias>(allow_alias_without_as_keyword),
std::make_unique<ParserExpressionWithOptionalAlias>(allow_alias_without_as_keyword, prefer_alias_to_column_name),
std::make_unique<ParserToken>(TokenType::Comma))
.parse(pos, node, expected);
}

View File

@ -311,7 +311,7 @@ using ParserExpression = ParserLambdaExpression;
class ParserExpressionWithOptionalAlias : public IParserBase
{
public:
ParserExpressionWithOptionalAlias(bool allow_alias_without_as_keyword);
ParserExpressionWithOptionalAlias(bool allow_alias_without_as_keyword, bool prefer_alias_to_column_name_ = false);
protected:
ParserPtr impl;
@ -343,11 +343,12 @@ protected:
class ParserExpressionList : public IParserBase
{
public:
ParserExpressionList(bool allow_alias_without_as_keyword_)
: allow_alias_without_as_keyword(allow_alias_without_as_keyword_) {}
ParserExpressionList(bool allow_alias_without_as_keyword_, bool prefer_alias_to_column_name_ = false)
: allow_alias_without_as_keyword(allow_alias_without_as_keyword_), prefer_alias_to_column_name(prefer_alias_to_column_name_) {}
protected:
bool allow_alias_without_as_keyword;
bool prefer_alias_to_column_name;
const char * getName() const { return "list of expressions"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected);
@ -357,8 +358,8 @@ protected:
class ParserNotEmptyExpressionList : public IParserBase
{
public:
ParserNotEmptyExpressionList(bool allow_alias_without_as_keyword)
: nested_parser(allow_alias_without_as_keyword) {}
ParserNotEmptyExpressionList(bool allow_alias_without_as_keyword, bool prefer_alias_to_column_name = false)
: nested_parser(allow_alias_without_as_keyword, prefer_alias_to_column_name) {}
private:
ParserExpressionList nested_parser;
protected:

View File

@ -42,10 +42,20 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
ParserKeyword s_by("BY");
ParserNotEmptyExpressionList exp_list(false);
ParserNotEmptyExpressionList exp_list_for_former_with_clause(false, true); /// Set prefer_alias_to_column_name for each alias.
ParserNotEmptyExpressionList exp_list_for_select_clause(true); /// Allows aliases without AS keyword.
ParserExpression exp_elem;
ParserOrderByExpressionList order_list;
/// WITH expr list
{
if (s_with.ignore(pos, expected))
{
if (!exp_list_for_former_with_clause.parse(pos, select_query->with_expression_list, expected))
return false;
}
}
/// SELECT [DISTINCT] expr list
{
if (!s_select.ignore(pos, expected))
@ -175,6 +185,8 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
select_query->range = StringRange(begin, pos);
if (select_query->with_expression_list)
select_query->children.push_back(select_query->with_expression_list);
select_query->children.push_back(select_query->select_expression_list);
if (select_query->tables)
select_query->children.push_back(select_query->tables);