2017-04-01 09:19:00 +00:00
|
|
|
#include <Parsers/CommonParsers.h>
|
|
|
|
#include <Parsers/ExpressionElementParsers.h>
|
|
|
|
#include <Parsers/ExpressionListParsers.h>
|
|
|
|
#include <Parsers/ASTFunction.h>
|
|
|
|
#include <Parsers/ASTTablesInSelectQuery.h>
|
|
|
|
#include <Parsers/ParserSelectQuery.h>
|
|
|
|
#include <Parsers/ParserSampleRatio.h>
|
|
|
|
#include <Parsers/ParserTablesInSelectQuery.h>
|
2016-07-18 00:14:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
extern const int SYNTAX_ERROR;
|
2016-07-18 00:14:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-10 03:28:12 +00:00
|
|
|
bool ParserTableExpression::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
2016-07-18 00:14:24 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
auto res = std::make_shared<ASTTableExpression>();
|
|
|
|
|
2018-02-24 01:31:42 +00:00
|
|
|
if (!ParserWithOptionalAlias(std::make_unique<ParserSubquery>(), true).parse(pos, res->subquery, expected)
|
|
|
|
&& !ParserWithOptionalAlias(std::make_unique<ParserFunction>(), true).parse(pos, res->table_function, expected)
|
|
|
|
&& !ParserWithOptionalAlias(std::make_unique<ParserCompoundIdentifier>(), true).parse(pos, res->database_and_table_name, expected))
|
2017-04-01 07:20:54 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
/// FINAL
|
2017-07-10 03:28:12 +00:00
|
|
|
if (ParserKeyword("FINAL").ignore(pos, expected))
|
2017-04-01 07:20:54 +00:00
|
|
|
res->final = true;
|
|
|
|
|
|
|
|
/// SAMPLE number
|
2017-07-10 03:28:12 +00:00
|
|
|
if (ParserKeyword("SAMPLE").ignore(pos, expected))
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
ParserSampleRatio ratio;
|
|
|
|
|
2017-07-10 03:28:12 +00:00
|
|
|
if (!ratio.parse(pos, res->sample_size, expected))
|
2017-04-01 07:20:54 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
/// OFFSET number
|
2017-07-10 03:28:12 +00:00
|
|
|
if (ParserKeyword("OFFSET").ignore(pos, expected))
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2017-07-10 03:28:12 +00:00
|
|
|
if (!ratio.parse(pos, res->sample_offset, expected))
|
2017-04-01 07:20:54 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (res->database_and_table_name)
|
|
|
|
res->children.emplace_back(res->database_and_table_name);
|
|
|
|
if (res->table_function)
|
|
|
|
res->children.emplace_back(res->table_function);
|
|
|
|
if (res->subquery)
|
|
|
|
res->children.emplace_back(res->subquery);
|
|
|
|
if (res->sample_size)
|
|
|
|
res->children.emplace_back(res->sample_size);
|
|
|
|
if (res->sample_offset)
|
|
|
|
res->children.emplace_back(res->sample_offset);
|
|
|
|
|
|
|
|
node = res;
|
|
|
|
return true;
|
2016-07-18 00:14:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-10 03:28:12 +00:00
|
|
|
bool ParserArrayJoin::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
2016-07-18 00:14:24 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
auto res = std::make_shared<ASTArrayJoin>();
|
|
|
|
|
|
|
|
/// [LEFT] ARRAY JOIN expr list
|
|
|
|
Pos saved_pos = pos;
|
|
|
|
bool has_array_join = false;
|
|
|
|
|
2017-07-10 03:28:12 +00:00
|
|
|
if (ParserKeyword("LEFT ARRAY JOIN").ignore(pos, expected))
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
res->kind = ASTArrayJoin::Kind::Left;
|
|
|
|
has_array_join = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pos = saved_pos;
|
|
|
|
|
|
|
|
/// INNER may be specified explicitly, otherwise it is assumed as default.
|
2017-07-10 03:28:12 +00:00
|
|
|
ParserKeyword("INNER").ignore(pos, expected);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-07-10 03:28:12 +00:00
|
|
|
if (ParserKeyword("ARRAY JOIN").ignore(pos, expected))
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
res->kind = ASTArrayJoin::Kind::Inner;
|
|
|
|
has_array_join = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!has_array_join)
|
|
|
|
return false;
|
|
|
|
|
2017-07-10 03:28:12 +00:00
|
|
|
if (!ParserExpressionList(false).parse(pos, res->expression_list, expected))
|
2017-04-01 07:20:54 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (res->expression_list)
|
|
|
|
res->children.emplace_back(res->expression_list);
|
|
|
|
|
|
|
|
node = res;
|
|
|
|
return true;
|
2016-07-18 00:14:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-10 03:28:12 +00:00
|
|
|
bool ParserTablesInSelectQueryElement::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
2016-07-18 00:14:24 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
auto res = std::make_shared<ASTTablesInSelectQueryElement>();
|
|
|
|
|
Make malformed `array join` statement fail early
Currently array join clause that have no parent table can go through the parser and generates some confusing error.
```
create table aa (a Array(UInt64)) Engine=Memory;
select * from array join aa;
Received exception from server (version 1.1.54311):
Code: 208. DB::Exception: Received from localhost:9000, ::1. DB::Exception: No columns in nested table aa.
```
This patch makes it fail at client side.
```
Syntax error: failed at position 21:
select * from array join aa;
Expected one of: SAMPLE, INNER, WITH, HAVING, SETTINGS, identifier, Dot, ORDER BY, AS, GROUP BY, INTO OUTFILE, UNION ALL, LEFT ARRAY JOIN, ARRAY JOIN, table, table function, subquery or list of joined tables, array join, alias, FINAL, PREWHERE, WHERE, token, FORMAT, LIMIT
```
However I'm not sure if `ParserCompoundIdentifier` should be stricter so that `array` wouldn't be consider as a table name.
2017-11-21 07:16:15 +00:00
|
|
|
if (is_first)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2017-07-10 03:28:12 +00:00
|
|
|
if (!ParserTableExpression().parse(pos, res->table_expression, expected))
|
2017-04-01 07:20:54 +00:00
|
|
|
return false;
|
|
|
|
}
|
Make malformed `array join` statement fail early
Currently array join clause that have no parent table can go through the parser and generates some confusing error.
```
create table aa (a Array(UInt64)) Engine=Memory;
select * from array join aa;
Received exception from server (version 1.1.54311):
Code: 208. DB::Exception: Received from localhost:9000, ::1. DB::Exception: No columns in nested table aa.
```
This patch makes it fail at client side.
```
Syntax error: failed at position 21:
select * from array join aa;
Expected one of: SAMPLE, INNER, WITH, HAVING, SETTINGS, identifier, Dot, ORDER BY, AS, GROUP BY, INTO OUTFILE, UNION ALL, LEFT ARRAY JOIN, ARRAY JOIN, table, table function, subquery or list of joined tables, array join, alias, FINAL, PREWHERE, WHERE, token, FORMAT, LIMIT
```
However I'm not sure if `ParserCompoundIdentifier` should be stricter so that `array` wouldn't be consider as a table name.
2017-11-21 07:16:15 +00:00
|
|
|
else if (ParserArrayJoin().parse(pos, res->array_join, expected))
|
|
|
|
{
|
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
auto table_join = std::make_shared<ASTTableJoin>();
|
|
|
|
|
2017-07-10 03:28:12 +00:00
|
|
|
if (pos->type == TokenType::Comma)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2017-07-10 03:28:12 +00:00
|
|
|
++pos;
|
2017-04-01 07:20:54 +00:00
|
|
|
table_join->kind = ASTTableJoin::Kind::Comma;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-07-10 03:28:12 +00:00
|
|
|
if (ParserKeyword("GLOBAL").ignore(pos))
|
2017-04-01 07:20:54 +00:00
|
|
|
table_join->locality = ASTTableJoin::Locality::Global;
|
2017-07-10 03:28:12 +00:00
|
|
|
else if (ParserKeyword("LOCAL").ignore(pos))
|
2017-04-01 07:20:54 +00:00
|
|
|
table_join->locality = ASTTableJoin::Locality::Local;
|
|
|
|
|
2017-07-10 03:28:12 +00:00
|
|
|
if (ParserKeyword("ANY").ignore(pos))
|
2017-04-01 07:20:54 +00:00
|
|
|
table_join->strictness = ASTTableJoin::Strictness::Any;
|
2017-07-10 03:28:12 +00:00
|
|
|
else if (ParserKeyword("ALL").ignore(pos))
|
2017-04-01 07:20:54 +00:00
|
|
|
table_join->strictness = ASTTableJoin::Strictness::All;
|
2019-03-20 16:58:28 +00:00
|
|
|
else if (ParserKeyword("ASOF").ignore(pos))
|
|
|
|
table_join->strictness = ASTTableJoin::Strictness::Asof;
|
2018-08-28 13:57:31 +00:00
|
|
|
else
|
|
|
|
table_join->strictness = ASTTableJoin::Strictness::Unspecified;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-07-10 03:28:12 +00:00
|
|
|
if (ParserKeyword("INNER").ignore(pos))
|
2017-04-01 07:20:54 +00:00
|
|
|
table_join->kind = ASTTableJoin::Kind::Inner;
|
2017-07-10 03:28:12 +00:00
|
|
|
else if (ParserKeyword("LEFT").ignore(pos))
|
2017-04-01 07:20:54 +00:00
|
|
|
table_join->kind = ASTTableJoin::Kind::Left;
|
2017-07-10 03:28:12 +00:00
|
|
|
else if (ParserKeyword("RIGHT").ignore(pos))
|
2017-04-01 07:20:54 +00:00
|
|
|
table_join->kind = ASTTableJoin::Kind::Right;
|
2017-07-10 03:28:12 +00:00
|
|
|
else if (ParserKeyword("FULL").ignore(pos))
|
2017-04-01 07:20:54 +00:00
|
|
|
table_join->kind = ASTTableJoin::Kind::Full;
|
2017-07-10 03:28:12 +00:00
|
|
|
else if (ParserKeyword("CROSS").ignore(pos))
|
2017-04-01 07:20:54 +00:00
|
|
|
table_join->kind = ASTTableJoin::Kind::Cross;
|
|
|
|
else
|
|
|
|
{
|
2018-09-17 13:33:19 +00:00
|
|
|
/// Use INNER by default as in another DBMS.
|
2018-09-17 08:20:46 +00:00
|
|
|
table_join->kind = ASTTableJoin::Kind::Inner;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (table_join->strictness != ASTTableJoin::Strictness::Unspecified
|
|
|
|
&& table_join->kind == ASTTableJoin::Kind::Cross)
|
|
|
|
throw Exception("You must not specify ANY or ALL for CROSS JOIN.", ErrorCodes::SYNTAX_ERROR);
|
|
|
|
|
|
|
|
/// Optional OUTER keyword for outer joins.
|
|
|
|
if (table_join->kind == ASTTableJoin::Kind::Left
|
|
|
|
|| table_join->kind == ASTTableJoin::Kind::Right
|
|
|
|
|| table_join->kind == ASTTableJoin::Kind::Full)
|
|
|
|
{
|
2017-07-10 03:28:12 +00:00
|
|
|
ParserKeyword("OUTER").ignore(pos);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
2017-07-10 03:28:12 +00:00
|
|
|
if (!ParserKeyword("JOIN").ignore(pos, expected))
|
2017-04-01 07:20:54 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-07-10 03:28:12 +00:00
|
|
|
if (!ParserTableExpression().parse(pos, res->table_expression, expected))
|
2017-04-01 07:20:54 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (table_join->kind != ASTTableJoin::Kind::Comma
|
|
|
|
&& table_join->kind != ASTTableJoin::Kind::Cross)
|
|
|
|
{
|
2017-07-10 03:28:12 +00:00
|
|
|
if (ParserKeyword("USING").ignore(pos, expected))
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
/// Expression for USING could be in parentheses or not.
|
2017-07-10 03:28:12 +00:00
|
|
|
bool in_parens = pos->type == TokenType::OpeningRoundBracket;
|
2017-04-01 07:20:54 +00:00
|
|
|
if (in_parens)
|
2017-07-10 03:28:12 +00:00
|
|
|
++pos;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-07-10 03:28:12 +00:00
|
|
|
if (!ParserExpressionList(false).parse(pos, table_join->using_expression_list, expected))
|
2017-04-01 07:20:54 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (in_parens)
|
|
|
|
{
|
2017-07-10 03:28:12 +00:00
|
|
|
if (pos->type != TokenType::ClosingRoundBracket)
|
2017-04-01 07:20:54 +00:00
|
|
|
return false;
|
2017-07-10 03:28:12 +00:00
|
|
|
++pos;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
}
|
2017-07-10 03:28:12 +00:00
|
|
|
else if (ParserKeyword("ON").ignore(pos, expected))
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
/// OR is operator with lowest priority, so start parsing from it.
|
2017-07-10 03:28:12 +00:00
|
|
|
if (!ParserLogicalOrExpression().parse(pos, table_join->on_expression, expected))
|
2017-04-01 07:20:54 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (table_join->using_expression_list)
|
|
|
|
table_join->children.emplace_back(table_join->using_expression_list);
|
|
|
|
if (table_join->on_expression)
|
|
|
|
table_join->children.emplace_back(table_join->on_expression);
|
|
|
|
|
|
|
|
res->table_join = table_join;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (res->table_expression)
|
|
|
|
res->children.emplace_back(res->table_expression);
|
|
|
|
if (res->table_join)
|
|
|
|
res->children.emplace_back(res->table_join);
|
|
|
|
if (res->array_join)
|
|
|
|
res->children.emplace_back(res->array_join);
|
|
|
|
|
|
|
|
node = res;
|
|
|
|
return true;
|
2016-07-18 00:14:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-10 03:28:12 +00:00
|
|
|
bool ParserTablesInSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
2016-07-18 00:14:24 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
auto res = std::make_shared<ASTTablesInSelectQuery>();
|
2016-07-18 00:14:24 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
ASTPtr child;
|
2016-07-18 00:14:24 +00:00
|
|
|
|
2017-07-10 03:28:12 +00:00
|
|
|
if (ParserTablesInSelectQueryElement(true).parse(pos, child, expected))
|
2017-04-01 07:20:54 +00:00
|
|
|
res->children.emplace_back(child);
|
|
|
|
else
|
|
|
|
return false;
|
2016-07-18 00:14:24 +00:00
|
|
|
|
2017-07-10 03:28:12 +00:00
|
|
|
while (ParserTablesInSelectQueryElement(false).parse(pos, child, expected))
|
2017-04-01 07:20:54 +00:00
|
|
|
res->children.emplace_back(child);
|
2016-07-18 00:14:24 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
node = res;
|
|
|
|
return true;
|
2016-07-18 00:14:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|