Rectification of JOINs [#METR-2944].

This commit is contained in:
Alexey Milovidov 2016-07-18 04:20:53 +03:00
parent 40ae51e7b3
commit 9f9be1b7fc
6 changed files with 56 additions and 186 deletions

View File

@ -94,7 +94,6 @@ add_library (dbms
include/DB/Parsers/ASTSubquery.h
include/DB/Parsers/ASTUseQuery.h
include/DB/Parsers/ASTIdentifier.h
include/DB/Parsers/ParserJoin.h
include/DB/Parsers/ParserTablePropertiesQuery.h
include/DB/Parsers/ASTJoin.h
include/DB/Parsers/ParserCheckQuery.h
@ -790,7 +789,6 @@ add_library (dbms
src/Parsers/ParserQueryWithOutput.cpp
src/Parsers/ParserCreateQuery.cpp
src/Parsers/ParserSelectQuery.cpp
src/Parsers/ParserJoin.cpp
src/Parsers/ParserInsertQuery.cpp
src/Parsers/ParserDropQuery.cpp
src/Parsers/ParserRenameQuery.cpp

View File

@ -1,17 +0,0 @@
#pragma once
#include <DB/Parsers/IParserBase.h>
namespace DB
{
class ParserJoin : public IParserBase
{
protected:
const char * getName() const { return "JOIN"; }
bool parseImpl(Pos & pos, Pos end, ASTPtr & node, Pos & max_parsed_pos, Expected & expected);
};
}

View File

@ -119,21 +119,55 @@ void ASTTableJoin::formatImplBeforeTable(const FormatSettings & settings, Format
{
settings.ostr << (settings.hilite ? hilite_keyword : "");
if (locality == Locality::Global)
settings.ostr << "GLOBAL ";
switch (locality)
{
case Locality::Unspecified:
break;
case Locality::Local:
break;
case Locality::Global:
settings.ostr << "GLOBAL ";
break;
}
if (kind != Kind::Cross && kind != Kind::Comma)
settings.ostr << (strictness == Strictness::Any ? "ANY " : "ALL ");
{
switch (strictness)
{
case Strictness::Unspecified:
break;
case Strictness::Any:
settings.ostr << "ANY ";
break;
case Strictness::All:
settings.ostr << "ALL ";
break;
}
}
settings.ostr <<
(kind == Kind::Inner ? "INNER"
: (kind == Kind::Left ? "LEFT"
: (kind == Kind::Right ? "RIGHT"
: (kind == Kind::Cross ? "CROSS"
: "FULL OUTER"))));
switch (kind)
{
case Kind::Inner:
settings.ostr << "INNER JOIN";
break;
case Kind::Left:
settings.ostr << "LEFT JOIN";
break;
case Kind::Right:
settings.ostr << "RIGHT JOIN";
break;
case Kind::Full:
settings.ostr << "FULL OUTER JOIN";
break;
case Kind::Cross:
settings.ostr << "CROSS JOIN";
break;
case Kind::Comma:
settings.ostr << ",";
break;
}
settings.ostr << " JOIN "
<< (settings.hilite ? hilite_none : "");
settings.ostr << (settings.hilite ? hilite_none : "");
}
@ -143,14 +177,14 @@ void ASTTableJoin::formatImplAfterTable(const FormatSettings & settings, FormatS
if (using_expression_list)
{
settings.ostr << (settings.hilite ? hilite_keyword : "") << " USING " << (settings.hilite ? hilite_none : "");
settings.ostr << (settings.hilite ? hilite_keyword : "") << "USING " << (settings.hilite ? hilite_none : "");
settings.ostr << "(";
using_expression_list->formatImpl(settings, state, frame);
settings.ostr << ")";
}
else if (on_expression)
{
settings.ostr << (settings.hilite ? hilite_keyword : "") << " ON " << (settings.hilite ? hilite_none : "");
settings.ostr << (settings.hilite ? hilite_keyword : "") << "ON " << (settings.hilite ? hilite_none : "");
on_expression->formatImpl(settings, state, frame);
}
}
@ -180,12 +214,14 @@ void ASTTablesInSelectQueryElement::formatImpl(const FormatSettings & settings,
if (table_expression)
{
if (table_join)
{
static_cast<const ASTTableJoin &>(*table_join).formatImplBeforeTable(settings, state, frame);
settings.ostr << " ";
}
settings.ostr << " ";
table_expression->formatImpl(settings, state, frame);
settings.ostr << " ";
if (table_join)
static_cast<const ASTTableJoin &>(*table_join).formatImplAfterTable(settings, state, frame);
}

View File

@ -1,148 +0,0 @@
#include <DB/Parsers/ASTJoin.h>
#include <DB/Parsers/CommonParsers.h>
#include <DB/Parsers/ExpressionElementParsers.h>
#include <DB/Parsers/ExpressionListParsers.h>
#include <DB/Parsers/ParserJoin.h>
namespace DB
{
namespace ErrorCodes
{
extern const int SYNTAX_ERROR;
}
bool ParserJoin::parseImpl(Pos & pos, Pos end, ASTPtr & node, Pos & max_parsed_pos, Expected & expected)
{
Pos begin = pos;
auto join = std::make_shared<ASTJoin>(StringRange(begin, pos));
node = join;
ParserWhiteSpaceOrComments ws;
ParserString s_global("GLOBAL", true, true);
ParserString s_any("ANY", true, true);
ParserString s_all("ALL", true, true);
ParserString s_inner("INNER", true, true);
ParserString s_left("LEFT", true, true);
ParserString s_right("RIGHT", true, true);
ParserString s_full("FULL", true, true);
ParserString s_cross("CROSS", true, true);
ParserString s_outer("OUTER", true, true);
ParserString s_join("JOIN", true, true);
ParserString s_using("USING", true, true);
ParserString s_on("ON", true, true);
ParserNotEmptyExpressionList exp_list(false);
ParserLogicalOrExpression exp_elem;
ParserWithOptionalAlias subquery(ParserPtr(new ParserSubquery), true);
ParserIdentifier identifier;
ws.ignore(pos, end);
if (s_global.ignore(pos, end))
join->locality = ASTJoin::Global;
else
join->locality = ASTJoin::Local;
ws.ignore(pos, end);
bool has_strictness = true;
if (s_any.ignore(pos, end))
join->strictness = ASTJoin::Any;
else if (s_all.ignore(pos, end))
join->strictness = ASTJoin::All;
else
has_strictness = false;
ws.ignore(pos, end);
if (s_inner.ignore(pos, end))
join->kind = ASTJoin::Inner;
else if (s_left.ignore(pos, end))
join->kind = ASTJoin::Left;
else if (s_right.ignore(pos, end))
join->kind = ASTJoin::Right;
else if (s_full.ignore(pos, end))
join->kind = ASTJoin::Full;
else if (s_cross.ignore(pos, end))
join->kind = ASTJoin::Cross;
else
{
expected = "INNER|LEFT|RIGHT|FULL|CROSS";
return false;
}
if (!has_strictness && join->kind != ASTJoin::Cross)
throw Exception("You must specify ANY or ALL for JOIN, before INNER or LEFT or RIGHT or FULL.", ErrorCodes::SYNTAX_ERROR);
if (has_strictness && join->kind == ASTJoin::Cross)
throw Exception("You must not specify ANY or ALL for CROSS JOIN.", ErrorCodes::SYNTAX_ERROR);
ws.ignore(pos, end);
/// Для всех JOIN-ов кроме INNER и CROSS может присутствовать не обязательное слово "OUTER".
if (join->kind != ASTJoin::Inner && join->kind != ASTJoin::Cross && s_outer.ignore(pos, end))
ws.ignore(pos, end);
if (!s_join.ignore(pos, end, max_parsed_pos, expected))
return false;
ws.ignore(pos, end);
if (!identifier.parse(pos, end, join->table, max_parsed_pos, expected)
&& !subquery.parse(pos, end, join->table, max_parsed_pos, expected))
return false;
ws.ignore(pos, end);
if (join->kind != ASTJoin::Cross)
{
if (s_using.ignore(pos, end, max_parsed_pos, expected))
{
ws.ignore(pos, end);
/// Выражение для USING можно указать как в скобках, так и без них.
bool in_parens = ParserString("(").ignore(pos, end);
if (in_parens)
ws.ignore(pos, end);
if (!exp_list.parse(pos, end, join->using_expr_list, max_parsed_pos, expected))
return false;
if (in_parens)
{
ws.ignore(pos, end);
if (!ParserString(")").ignore(pos, end))
return false;
}
ws.ignore(pos, end);
}
else if (s_on.ignore(pos, end, max_parsed_pos, expected))
{
ws.ignore(pos, end);
if (!exp_elem.parse(pos, end, join->on_expr, max_parsed_pos, expected))
return false;
ws.ignore(pos, end);
}
else
{
expected = "USING or ON";
return false;
}
}
join->children.push_back(join->table);
if (join->using_expr_list)
join->children.push_back(join->using_expr_list);
return true;
}
}

View File

@ -5,7 +5,6 @@
#include <DB/Parsers/CommonParsers.h>
#include <DB/Parsers/ExpressionElementParsers.h>
#include <DB/Parsers/ExpressionListParsers.h>
#include <DB/Parsers/ParserJoin.h>
#include <DB/Parsers/ParserSetQuery.h>
#include <DB/Parsers/ParserSampleRatio.h>
#include <DB/Parsers/ParserSelectQuery.h>
@ -47,7 +46,6 @@ bool ParserSelectQuery::parseImpl(Pos & pos, Pos end, ASTPtr & node, Pos & max_p
ParserNotEmptyExpressionList exp_list(false);
ParserNotEmptyExpressionList exp_list_for_select_clause(true); /// Allows aliases without AS keyword.
ParserExpressionWithOptionalAlias exp_elem(false);
ParserJoin join;
ParserOrderByExpressionList order_list;
ws.ignore(pos, end);

View File

@ -32,7 +32,8 @@ bool ParserTableExpression::parseImpl(Pos & pos, Pos end, ASTPtr & node, Pos & m
{
static_cast<ASTFunction &>(*res->table_function).kind = ASTFunction::TABLE_FUNCTION;
}
else if (ParserCompoundIdentifier().parse(pos, end, res->database_and_table_name, max_parsed_pos, expected))
else if (ParserWithOptionalAlias(std::make_unique<ParserCompoundIdentifier>(), true)
.parse(pos, end, res->database_and_table_name, max_parsed_pos, expected))
{
static_cast<ASTIdentifier &>(*res->database_and_table_name).kind = ASTIdentifier::Table;
}
@ -243,7 +244,8 @@ bool ParserTablesInSelectQueryElement::parseImpl(Pos & pos, Pos end, ASTPtr & no
{
ws.ignore(pos, end);
if (!ParserExpressionElement().parse(pos, end, table_join->on_expression, max_parsed_pos, expected))
/// OR is operator with lowest priority, so start parsing from it.
if (!ParserLogicalOrExpression().parse(pos, end, table_join->on_expression, max_parsed_pos, expected))
return false;
ws.ignore(pos, end);
@ -291,6 +293,7 @@ bool ParserTablesInSelectQuery::parseImpl(Pos & pos, Pos end, ASTPtr & node, Pos
while (ParserTablesInSelectQueryElement(false).parse(pos, end, child, max_parsed_pos, expected))
res->children.emplace_back(child);
node = res;
return true;
}