disable asterisks in mJOIN, add some tests

This commit is contained in:
chertus 2019-02-20 18:28:53 +03:00
parent d45d980716
commit 1f2a5f9a91
4 changed files with 161 additions and 54 deletions

View File

@ -21,6 +21,7 @@ namespace ErrorCodes
extern const int LOGICAL_ERROR;
extern const int TOO_DEEP_AST;
extern const int AMBIGUOUS_COLUMN_NAME;
extern const int NOT_IMPLEMENTED;
}
namespace
@ -29,27 +30,78 @@ namespace
/// Find columns with aliases to push them into rewritten subselects.
/// Normalize table aliases: table_name.column_name -> table_alias.column_name
/// Make aliases maps (alias -> column_name, column_name -> alias)
struct ColumnAliasesVisitorData
struct ColumnAliasesMatcher
{
using TypeToVisit = ASTIdentifier;
struct Data
{
const std::vector<DatabaseAndTableWithAlias> tables;
AsteriskSemantic::RevertedAliases rev_aliases;
std::unordered_map<String, String> aliases;
std::vector<ASTIdentifier *> compound_identifiers;
const std::vector<DatabaseAndTableWithAlias> tables;
AsteriskSemantic::RevertedAliases rev_aliases;
std::unordered_map<String, String> aliases;
std::vector<ASTIdentifier *> compound_identifiers;
Data(std::vector<DatabaseAndTableWithAlias> && tables_)
: tables(tables_)
{}
ColumnAliasesVisitorData(std::vector<DatabaseAndTableWithAlias> && tables_)
: tables(tables_)
{}
void replaceIdentifiersWithAliases()
{
String hide_prefix = "--"; /// @note restriction: user should not use alises like `--table.column`
void visit(ASTIdentifier & node, ASTPtr &)
for (auto * identifier : compound_identifiers)
{
auto it = rev_aliases.find(identifier->name);
if (it == rev_aliases.end())
{
bool last_table = IdentifierSemantic::canReferColumnToTable(*identifier, tables.back());
if (!last_table)
{
String long_name = identifier->name;
String alias = hide_prefix + long_name;
aliases[alias] = long_name;
rev_aliases[long_name].push_back(alias);
identifier->setShortName(alias);
//identifier->setAlias(long_name);
}
}
else
{
if (it->second.empty())
throw Exception("No alias for '" + identifier->name + "'", ErrorCodes::LOGICAL_ERROR);
identifier->setShortName(it->second[0]);
}
}
}
};
static constexpr const char * label = "ColumnAliases";
static bool needChildVisit(ASTPtr & node, const ASTPtr &)
{
if (typeid_cast<const ASTQualifiedAsterisk *>(node.get()))
return false;
return true;
}
static std::vector<ASTPtr *> visit(ASTPtr & ast, Data & data)
{
if (auto * t = typeid_cast<ASTIdentifier *>(ast.get()))
visit(*t, ast, data);
if (typeid_cast<ASTAsterisk *>(ast.get()) ||
typeid_cast<ASTQualifiedAsterisk *>(ast.get()))
throw Exception("Multiple JOIN do not support asterisks yet", ErrorCodes::NOT_IMPLEMENTED);
return {};
}
static void visit(ASTIdentifier & node, ASTPtr &, Data & data)
{
if (node.isShort())
return;
bool last_table = false;
String long_name;
for (auto & table : tables)
for (auto & table : data.tables)
{
if (IdentifierSemantic::canReferColumnToTable(node, table))
{
@ -57,7 +109,7 @@ struct ColumnAliasesVisitorData
throw Exception("Cannot refer column '" + node.name + "' to one table", ErrorCodes::AMBIGUOUS_COLUMN_NAME);
IdentifierSemantic::setColumnLongName(node, table); /// table_name.column_name -> table_alias.column_name
long_name = node.name;
if (&table == &tables.back())
if (&table == &data.tables.back())
last_table = true;
}
}
@ -68,8 +120,8 @@ struct ColumnAliasesVisitorData
String alias = node.tryGetAlias();
if (!alias.empty())
{
aliases[alias] = long_name;
rev_aliases[long_name].push_back(alias);
data.aliases[alias] = long_name;
data.rev_aliases[long_name].push_back(alias);
if (!last_table)
{
@ -78,37 +130,7 @@ struct ColumnAliasesVisitorData
}
}
else
compound_identifiers.push_back(&node);
}
void replaceIdentifiersWithAliases()
{
String hide_prefix = "--"; /// @note restriction: user should not use alises like `--table.column`
for (auto * identifier : compound_identifiers)
{
auto it = rev_aliases.find(identifier->name);
if (it == rev_aliases.end())
{
bool last_table = IdentifierSemantic::canReferColumnToTable(*identifier, tables.back());
if (!last_table)
{
String long_name = identifier->name;
String alias = hide_prefix + long_name;
aliases[alias] = long_name;
rev_aliases[long_name].push_back(alias);
identifier->setShortName(alias);
identifier->setAlias(long_name);
}
}
else
{
if (it->second.empty())
throw Exception("No alias for '" + identifier->name + "'", ErrorCodes::LOGICAL_ERROR);
identifier->setShortName(it->second[0]);
}
}
data.compound_identifiers.push_back(&node);
}
};
@ -179,11 +201,11 @@ bool needRewrite(ASTSelectQuery & select)
auto join = typeid_cast<const ASTTableJoin *>(table->table_join.get());
if (join->kind == ASTTableJoin::Kind::Comma)
throw Exception("Multiple COMMA JOIN is not supported", ErrorCodes::LOGICAL_ERROR);
throw Exception("Multiple COMMA JOIN is not supported", ErrorCodes::NOT_IMPLEMENTED);
/// it's not trivial to support mix of JOIN ON & JOIN USING cause of short names
if (!join || !join->on_expression)
throw Exception("Multiple JOIN expects JOIN with ON section", ErrorCodes::LOGICAL_ERROR);
throw Exception("Multiple JOIN expects JOIN with ON section", ErrorCodes::NOT_IMPLEMENTED);
}
return true;
@ -191,7 +213,6 @@ bool needRewrite(ASTSelectQuery & select)
using RewriteMatcher = OneTypeMatcher<RewriteTablesVisitorData>;
using RewriteVisitor = InDepthNodeVisitor<RewriteMatcher, true>;
using ColumnAliasesMatcher = OneTypeMatcher<ColumnAliasesVisitorData>;
using ColumnAliasesVisitor = InDepthNodeVisitor<ColumnAliasesMatcher, true>;
using AppendSemanticMatcher = OneTypeMatcher<AppendSemanticVisitorData>;
using AppendSemanticVisitor = InDepthNodeVisitor<AppendSemanticMatcher, true>;

View File

@ -231,7 +231,8 @@ static const ASTTablesInSelectQueryElement * getFirstTableJoin(const ASTSelectQu
if (!joined_table)
joined_table = &tables_element;
else
throw Exception("Support for more than one JOIN in query is not implemented", ErrorCodes::NOT_IMPLEMENTED);
throw Exception("Multiple JOIN disabled or does not support the query. "
"'set allow_experimental_multiple_joins_emulation' to enable.", ErrorCodes::NOT_IMPLEMENTED);
}
}

View File

@ -2,6 +2,38 @@
6 60 600
12 120 1200
18 180 1800
-
0 0 0
10 100 1000
20 200 2000
-
0 0 0
-
0 0 0 0
6 6 60 60
12 12 120 120
18 18 180 180
0 0 0 0
6 6 60 60
12 12 120 120
18 18 180 180
0 0 0 0
6 6 60 60
12 12 120 120
18 18 180 180
0 0 0 0
6 6 60 60
12 12 120 120
18 18 180 180
0 0 0 0
6 6 60 60
12 12 120 120
18 18 180 180
0 0 0 0
6 6 60 60
12 12 120 120
18 18 180 180
0 0 0 0 0 0 0
6 6 60 60 66 66 120
12 12 120 120 132 132 240
18 18 180 180 198 198 360

View File

@ -17,12 +17,65 @@ INSERT INTO table5 SELECT number * 5, number * 50, number * 500 FROM numbers(10)
SET allow_experimental_multiple_joins_emulation = 1;
SELECT 1 LIMIT 0;
select t1.a, t2.b, t3.c from table1 as t1 join table2 as t2 on t1.a = t2.a join table3 as t3 on t2.b = t3.b;
select '-';
select t1.a, t2.b, t5.c from table1 as t1 join table2 as t2 on t1.a = t2.a join table5 as t5 on t1.a = t5.a AND t2.b = t5.b;
select '-';
select t1.a, t2.b, t3.c from table1 as t1 join table2 as t2 on t1.a = t2.a join table3 as t3 on t2.b = t3.b join table5 as t5 on t3.c = t5.c;
select '-';
-- FIXME: wrong names qualification
select a, b, c from table1 as t1 join table2 as t2 on t1.a = t2.a join table3 as t3 on b = t3.b;
select a, b, c from table1 as t1 join table2 as t2 on t1.a = t2.a join table5 as t5 on a = t5.a AND b = t5.b;
--select a, b, c from table1 as t1 join table2 as t2 on t1.a = t2.a join table3 as t3 on b = t3.b join table5 as t5 on c = t5.c;
select t1.a as t1_a, t2.a as t2_a, t2.b as t2_b, t3.b as t3_b
from table1 as t1
join table2 as t2 on t1_a = t2_a
join table3 as t3 on t2_b = t3_b;
select t1.a as t1_a, t2.a as t2_a, t2.b as t2_b, t3.b as t3_b
from table1 as t1
join table2 as t2 on t1.a = t2.a
join table3 as t3 on t2.b = t3.b;
select t1.a as t1_a, t2.a as t2_a, t2.b as t2_b, t3.b as t3_b
from table1 as t1
join table2 as t2 on table1.a = table2.a
join table3 as t3 on table2.b = table3.b;
select t1.a, t2.a, t2.b, t3.b
from table1 as t1
join table2 as t2 on table1.a = table2.a
join table3 as t3 on table2.b = table3.b;
select t1.a, t2.a, t2.b, t3.b
from table1 as t1
join table2 as t2 on t1.a = t2.a
join table3 as t3 on t2.b = t3.b;
select table1.a, table2.a, table2.b, table3.b
from table1 as t1
join table2 as t2 on table1.a = table2.a
join table3 as t3 on table2.b = table3.b;
-- TODO
select t1.*, t2.*, t3.*
from table1 as t1
join table2 as t2 on table1.a = table2.a
join table3 as t3 on table2.b = table3.b; -- { serverError 48 }
-- TODO
select *
from table1 as t1
join table2 as t2 on t1.a = t2.a
join table3 as t3 on t2.b = t3.b; -- { serverError 48 }
select t1.a as t1_a, t2.a as t2_a, t2.b as t2_b, t3.b as t3_b,
(t1.a + table2.b) as t1_t2_x, (table1.a + table3.b) as t1_t3_x, (t2.b + t3.b) as t2_t3_x
from table1 as t1
join table2 as t2 on t1_a = t2_a
join table3 as t3 on t2_b = t3_b;
--select (t1.a + table2.b) as t1_t2_x, (table1.a + table3.b) as t1_t3_x, (t2.b + t3.b) as t2_t3_x
--from table1 as t1
--join table2 as t2 on t1_t2_x = t2.a
--join table3 as t3 on t1_t3_x = t2_t3_x;
DROP TABLE table1;
DROP TABLE table2;