Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion src/Interpreters/ClusterProxy/SelectStreamFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ ASTPtr rewriteSelectQuery(
const ASTPtr & query,
const std::string & remote_database,
const std::string & remote_table,
ASTPtr table_function_ptr)
ASTPtr table_function_ptr,
ASTPtr additional_filter)
{
auto modified_query_ast = query->clone();

Expand All @@ -80,8 +81,33 @@ ASTPtr rewriteSelectQuery(

if (!context->getSettingsRef()[Setting::allow_experimental_analyzer])
{
// Apply additional filter if provided
if (additional_filter)
{
if (select_query.where())
{
/// WHERE <old> AND <filter>
select_query.setExpression(
ASTSelectQuery::Expression::WHERE,
makeASTFunction("and", select_query.where(), additional_filter));
}
else
{
/// No WHERE – simply set it
select_query.setExpression(
ASTSelectQuery::Expression::WHERE, additional_filter->clone());
}
}

if (table_function_ptr)
{
select_query.addTableFunction(table_function_ptr);

// Reset semantic table information for all column identifiers to prevent
// RestoreQualifiedNamesVisitor from adding wrong table names
ResetSemanticTableVisitor::Data data;
ResetSemanticTableVisitor(data).visit(modified_query_ast);
}
else
select_query.replaceDatabaseAndTable(remote_database, remote_table);

Expand All @@ -93,6 +119,7 @@ ASTPtr rewriteSelectQuery(
data.distributed_table = DatabaseAndTableWithAlias(*getTableExpression(query->as<ASTSelectQuery &>(), 0));
data.remote_table.database = remote_database;
data.remote_table.table = remote_table;

RestoreQualifiedNamesVisitor(data).visit(modified_query_ast);
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/Interpreters/ClusterProxy/SelectStreamFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ ASTPtr rewriteSelectQuery(
const ASTPtr & query,
const std::string & remote_database,
const std::string & remote_table,
ASTPtr table_function_ptr = nullptr);
ASTPtr table_function_ptr = nullptr,
ASTPtr additional_filter = nullptr);

using ColumnsDescriptionByShardNum = std::unordered_map<UInt32, ColumnsDescription>;
using AdditionalShardFilterGenerator = std::function<ASTPtr(uint64_t)>;
Expand Down
11 changes: 11 additions & 0 deletions src/Interpreters/TranslateQualifiedNamesVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,4 +399,15 @@ void RestoreQualifiedNamesMatcher::visit(ASTIdentifier & identifier, ASTPtr &, D
}
}

void ResetSemanticTableMatcher::visit(ASTPtr & ast, Data & data)
{
if (auto * t = ast->as<ASTIdentifier>())
visit(*t, ast, data);
}

void ResetSemanticTableMatcher::visit(ASTIdentifier & identifier, ASTPtr &, Data &)
{
identifier.resetSemanticTable();
}

}
29 changes: 29 additions & 0 deletions src/Interpreters/TranslateQualifiedNamesVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,33 @@ struct RestoreQualifiedNamesMatcher

using RestoreQualifiedNamesVisitor = InDepthNodeVisitor<RestoreQualifiedNamesMatcher, true>;


/// Reset semantic->table for all column identifiers in the AST.
///
/// PROBLEM DESCRIPTION:
/// When an AST is passed through multiple query rewrites (e.g., in TieredDistributedMerge -> remote),
/// the semantic->table information attached to ASTIdentifier nodes can become stale and
/// cause incorrect column qualification. This happens because:
///
/// 1. During initial parsing, semantic->table is populated with the original table name
/// 2. When the query is rewritten (e.g., FROM clause changed from table to remote() function inside TieredDistributedMerge),
/// the AST structure is modified but semantic->table information is preserved
/// 3. Subsequent visitors like RestoreQualifiedNamesVisitor called in remote() function over the same AST
/// may use this stale semantic->table information to incorrectly qualify column names with the original table name
///
/// SOLUTION:
/// This visitor clears semantic->table for all column identifiers, ensuring that subsequent
/// visitors work with clean semantic information and don't apply stale table qualifications.
struct ResetSemanticTableMatcher
{
// No data needed for this visitor
struct Data {};

static bool needChildVisit(const ASTPtr &, const ASTPtr &) { return true; }
static void visit(ASTPtr & ast, Data & data);
static void visit(ASTIdentifier & identifier, ASTPtr &, Data & data);
};

using ResetSemanticTableVisitor = InDepthNodeVisitor<ResetSemanticTableMatcher, true>;

}
11 changes: 11 additions & 0 deletions src/Parsers/ASTIdentifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,17 @@ void ASTIdentifier::restoreTable()
}
}

void ASTIdentifier::resetSemanticTable()
{
// Only reset semantic table for column identifiers (not table identifiers)
if (semantic && !semantic->special)
{
semantic->table.clear();
semantic->can_be_alias = true;
semantic->membership = std::nullopt;
}
}

std::shared_ptr<ASTTableIdentifier> ASTIdentifier::createTable() const
{
if (name_parts.size() == 1) return std::make_shared<ASTTableIdentifier>(name_parts[0]);
Expand Down
1 change: 1 addition & 0 deletions src/Parsers/ASTIdentifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class ASTIdentifier : public ASTWithAlias
void updateTreeHashImpl(SipHash & hash_state, bool ignore_alias) const override;

void restoreTable(); // TODO(ilezhankin): get rid of this
void resetSemanticTable(); // Reset semantic to empty string (see ResetSemanticTableVisitor)
std::shared_ptr<ASTTableIdentifier> createTable() const; // returns |nullptr| if identifier is not table.

String full_name;
Expand Down
2 changes: 1 addition & 1 deletion src/Planner/PlannerActionsVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ class ActionNodeNameHelper
}
default:
{
throw Exception(ErrorCodes::LOGICAL_ERROR, "Invalid action query tree node {}", node->formatASTForErrorMessage());
throw Exception(ErrorCodes::LOGICAL_ERROR, "Invalid action query tree node {} (node_type: {})", node->formatASTForErrorMessage(), static_cast<int>(node_type));
}
}

Expand Down
Loading
Loading