MCPcopy Create free account
hub / github.com/ClickHouse/ClickHouse / inlineViewSubqueryIfNeeded

Method inlineViewSubqueryIfNeeded

src/Analyzer/Resolve/QueryAnalyzer.cpp:5427–5599  ·  view source on GitHub ↗

Try to expand an ordinary (non-materialized, non-parameterized) VIEW into an inline subquery. * This replaces the TableNode wrapping a StorageView with a QueryNode/UnionNode built from the * view's inner query AST, making the view transparent to the analyzer and all optimization passes. */

Source from the content-addressed store, hash-verified

5425 * view's inner query AST, making the view transparent to the analyzer and all optimization passes.
5426 */
5427void QueryAnalyzer::inlineViewSubqueryIfNeeded(QueryTreeNodePtr & join_tree_node, IdentifierResolveScope & scope) const
5428{
5429 if (!scope.context->getSettingsRef()[Setting::analyzer_inline_views])
5430 return;
5431
5432 auto * table_node = join_tree_node->as<TableNode>();
5433 if (!table_node)
5434 return;
5435
5436 const auto & storage = table_node->getStorage();
5437 const auto * view = typeid_cast<const StorageView *>(storage.get());
5438 if (!view || view->isParameterizedView())
5439 return;
5440
5441 /// Do not inline views with FINAL/SAMPLE modifiers for now.
5442 if (table_node->hasTableExpressionModifiers())
5443 return;
5444
5445 /// Get the view's inner query AST.
5446 const auto & storage_snapshot = table_node->getStorageSnapshot();
5447
5448 auto view_context = StorageView::getViewSubqueryContext(scope.context, storage_snapshot);
5449
5450 /// Check for row policies on the view itself.
5451 auto storage_id = storage->getStorageID();
5452 auto row_policy_filter = scope.context->getRowPolicyFilter(
5453 storage_id.getDatabaseName(), storage_id.getTableName(), RowPolicyFilterType::SELECT_FILTER);
5454 bool has_row_policy = row_policy_filter && !row_policy_filter->isAlwaysTrue();
5455
5456 /// Build the query tree from the view's inner query AST.
5457 ASTPtr view_ast = storage_snapshot->metadata->getSelectQuery().inner_query->clone();
5458 auto view_query_tree = buildQueryTree(view_ast, view_context);
5459 QueryAnalyzer view_analyzer(this->only_analyze);
5460 view_analyzer.resolve(view_query_tree, {}, view_context);
5461
5462 /// Mark the inlined query as a subquery so it is wrapped in parentheses when serialized to AST
5463 /// (e.g. for sending to parallel replicas). Without this, it produces `FROM SELECT ...` instead
5464 /// of `FROM (SELECT ...)`.
5465 if (auto * query_node = view_query_tree->as<QueryNode>())
5466 query_node->setIsSubquery(true);
5467 else if (auto * union_node = view_query_tree->as<UnionNode>())
5468 union_node->setIsSubquery(true);
5469
5470 /// The VIEW's declared column types may differ from what the inner subquery actually produces
5471 /// (e.g. the view was created with explicit column types, or implicit conversions apply).
5472 /// Normally StorageView adds a converting step in the query pipeline. When inlining, we must
5473 /// reproduce that by wrapping the subquery in SELECT CAST(col, 'ViewType') ... FROM (subquery).
5474 auto view_columns_list = storage_snapshot->metadata->getColumns().getOrdinary();
5475 NamesAndTypes view_columns(view_columns_list.begin(), view_columns_list.end());
5476
5477 NamesAndTypes subquery_columns;
5478 if (const auto * query_node = view_query_tree->as<QueryNode>())
5479 subquery_columns = query_node->getProjectionColumns();
5480 else if (const auto * union_node = view_query_tree->as<UnionNode>())
5481 subquery_columns = union_node->computeProjectionColumns();
5482
5483 bool needs_type_conversion = false;
5484 if (view_columns.size() == subquery_columns.size())

Callers

nothing calls this directly

Calls 15

buildQueryTreeFunction · 0.85
buildCastFunctionFunction · 0.85
isAlwaysTrueMethod · 0.80
getOrdinaryMethod · 0.80
getNodesMethod · 0.80
getProjectionMethod · 0.80
getStorageMethod · 0.45
getMethod · 0.45
isParameterizedViewMethod · 0.45

Tested by

no test coverage detected