mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-10 09:32:06 +00:00
safe tables order in select * with multiple joins
This commit is contained in:
parent
5295b89fd9
commit
e578020bd3
@ -33,30 +33,46 @@ namespace
|
||||
{
|
||||
|
||||
/// Replace asterisks in select_expression_list with column identifiers
|
||||
struct ExtractAsterisksMatcher
|
||||
class ExtractAsterisksMatcher
|
||||
{
|
||||
public:
|
||||
using Visitor = InDepthNodeVisitor<ExtractAsterisksMatcher, true>;
|
||||
|
||||
struct Data
|
||||
{
|
||||
std::unordered_map<String, NamesAndTypesList> table_columns;
|
||||
std::vector<String> tables_order;
|
||||
std::shared_ptr<ASTExpressionList> new_select_expression_list;
|
||||
|
||||
Data(const Context & context, const std::vector<const ASTTableExpression *> & table_expressions)
|
||||
{
|
||||
tables_order.reserve(table_expressions.size());
|
||||
for (const auto & expr : table_expressions)
|
||||
{
|
||||
if (expr->subquery)
|
||||
{
|
||||
table_columns.clear();
|
||||
tables_order.clear();
|
||||
break;
|
||||
}
|
||||
|
||||
String table_name = DatabaseAndTableWithAlias(*expr, context.getCurrentDatabase()).getQualifiedNamePrefix(false);
|
||||
NamesAndTypesList columns = getNamesAndTypeListFromTableExpression(*expr, context);
|
||||
tables_order.push_back(table_name);
|
||||
table_columns.emplace(std::move(table_name), std::move(columns));
|
||||
}
|
||||
}
|
||||
|
||||
void addTableColumns(const String & table_name)
|
||||
{
|
||||
auto it = table_columns.find(table_name);
|
||||
if (it == table_columns.end())
|
||||
throw Exception("Unknown qualified identifier: " + table_name, ErrorCodes::UNKNOWN_IDENTIFIER);
|
||||
|
||||
for (const auto & column : it->second)
|
||||
new_select_expression_list->children.push_back(
|
||||
std::make_shared<ASTIdentifier>(std::vector<String>{it->first, column.name}));
|
||||
}
|
||||
};
|
||||
|
||||
static bool needChildVisit(ASTPtr &, const ASTPtr &) { return false; }
|
||||
@ -69,6 +85,7 @@ struct ExtractAsterisksMatcher
|
||||
visit(*t, ast, data);
|
||||
}
|
||||
|
||||
private:
|
||||
static void visit(ASTSelectQuery & node, ASTPtr &, Data & data)
|
||||
{
|
||||
if (data.table_columns.empty())
|
||||
@ -101,10 +118,8 @@ struct ExtractAsterisksMatcher
|
||||
{
|
||||
has_asterisks = true;
|
||||
|
||||
for (auto & pr : data.table_columns)
|
||||
for (const auto & column : pr.second)
|
||||
data.new_select_expression_list->children.push_back(
|
||||
std::make_shared<ASTIdentifier>(std::vector<String>{pr.first, column.name}));
|
||||
for (auto & table_name : data.tables_order)
|
||||
data.addTableColumns(table_name);
|
||||
}
|
||||
else if (child->as<ASTQualifiedAsterisk>())
|
||||
{
|
||||
@ -114,13 +129,7 @@ struct ExtractAsterisksMatcher
|
||||
throw Exception("Logical error: qualified asterisk must have exactly one child", ErrorCodes::LOGICAL_ERROR);
|
||||
ASTIdentifier & identifier = child->children[0]->as<ASTIdentifier &>();
|
||||
|
||||
auto it = data.table_columns.find(identifier.name);
|
||||
if (it == data.table_columns.end())
|
||||
throw Exception("Unknown qualified identifier: " + identifier.name, ErrorCodes::UNKNOWN_IDENTIFIER);
|
||||
|
||||
for (const auto & column : it->second)
|
||||
data.new_select_expression_list->children.push_back(
|
||||
std::make_shared<ASTIdentifier>(std::vector<String>{it->first, column.name}));
|
||||
data.addTableColumns(identifier.name);
|
||||
}
|
||||
else
|
||||
data.new_select_expression_list->children.push_back(child);
|
||||
|
@ -32,14 +32,18 @@
|
||||
6 6 60 60
|
||||
12 12 120 120
|
||||
18 18 180 180
|
||||
0 0 0 0 0
|
||||
6 6 60 60 600
|
||||
12 12 120 120 1200
|
||||
18 18 180 180 1800
|
||||
0 0 0 0 0
|
||||
60 600 6 60 6
|
||||
120 1200 12 120 12
|
||||
180 1800 18 180 18
|
||||
┌─t1.a─┬─t2.a─┬─t2.b─┬─t3.b─┬─t3.c─┐
|
||||
│ 0 │ 0 │ 0 │ 0 │ 0 │
|
||||
│ 6 │ 6 │ 60 │ 60 │ 600 │
|
||||
│ 12 │ 12 │ 120 │ 120 │ 1200 │
|
||||
│ 18 │ 18 │ 180 │ 180 │ 1800 │
|
||||
└──────┴──────┴──────┴──────┴──────┘
|
||||
┌─t1.a─┬─t2.a─┬─t2.b─┬─t3.b─┬─t3.c─┐
|
||||
│ 0 │ 0 │ 0 │ 0 │ 0 │
|
||||
│ 6 │ 6 │ 60 │ 60 │ 600 │
|
||||
│ 12 │ 12 │ 120 │ 120 │ 1200 │
|
||||
│ 18 │ 18 │ 180 │ 180 │ 1800 │
|
||||
└──────┴──────┴──────┴──────┴──────┘
|
||||
0 0 0 0 0 0 0
|
||||
6 6 60 60 66 66 120
|
||||
12 12 120 120 132 132 240
|
||||
|
@ -60,12 +60,14 @@ join table3 as t3 on table2.b = table3.b;
|
||||
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;
|
||||
join table3 as t3 on table2.b = table3.b
|
||||
FORMAT PrettyCompactNoEscapes;
|
||||
|
||||
select *
|
||||
from table1 as t1
|
||||
join table2 as t2 on t1.a = t2.a
|
||||
join table3 as t3 on t2.b = t3.b;
|
||||
join table3 as t3 on t2.b = t3.b
|
||||
FORMAT PrettyCompactNoEscapes;
|
||||
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user