mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-22 07:31:57 +00:00
Rectification of JOINs [#METR-2944].
This commit is contained in:
parent
40ae51e7b3
commit
9f9be1b7fc
@ -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
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user