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

Method resolveMatcher

src/Analyzer/Resolve/QueryAnalyzer.cpp:2318–2784  ·  view source on GitHub ↗

Resolve query tree matcher. Check MatcherNode.h for detailed matcher description. Check ColumnTransformers.h for detailed transformers description. * * 1. Populate matched expression nodes resolving qualified or unqualified matcher. * 2. Apply column transformers to matched expression nodes. For strict column transformers save used column names. * 3. Validate strict column transformers.

Source from the content-addressed store, hash-verified

2316 * 3. Validate strict column transformers.
2317 */
2318ProjectionNames QueryAnalyzer::resolveMatcher(QueryTreeNodePtr & matcher_node, IdentifierResolveScope & scope)
2319{
2320 auto & matcher_node_typed = matcher_node->as<MatcherNode &>();
2321
2322 std::unordered_map<std::string, QueryTreeNodePtr> replace_transformer_mappings;
2323
2324 QueryTreeNodesWithNames matched_expression_nodes_with_names;
2325
2326 if (matcher_node_typed.isQualified())
2327 matched_expression_nodes_with_names = resolveQualifiedMatcher(matcher_node, scope);
2328 else
2329 matched_expression_nodes_with_names = resolveUnqualifiedMatcher(matcher_node, scope);
2330
2331 if (scope.join_use_nulls)
2332 {
2333 /** If we are resolving matcher came from the result of JOIN and `join_use_nulls` is set,
2334 * we need to convert joined column type to Nullable.
2335 * We are checking all registered_table_expression_nodes which contains all table expressions that are used to resolve matcher.
2336 * If it's on null side, we need to convert column type to Nullable.
2337 */
2338 for (const auto & table_expression : scope.registered_table_expression_nodes)
2339 {
2340 const JoinNode * nearest_scope_join_node = table_expression->as<JoinNode>();
2341 if (!nearest_scope_join_node)
2342 continue;
2343
2344 for (auto & [node, node_name] : matched_expression_nodes_with_names)
2345 {
2346 auto join_identifier_side = getColumnSideFromJoinTree(node, *nearest_scope_join_node);
2347 if (!join_identifier_side)
2348 continue;
2349 auto projection_name_it = node_to_projection_name.find(node);
2350 auto nullable_node = IdentifierResolver::convertJoinedColumnTypeToNullIfNeeded(node, node->getResultType(), nearest_scope_join_node->getKind(), join_identifier_side, scope);
2351 if (nullable_node)
2352 {
2353 node = nullable_node;
2354 /// Set the same projection name for new nullable node
2355 if (projection_name_it != node_to_projection_name.end())
2356 {
2357 node_to_projection_name.emplace(node, projection_name_it->second);
2358 }
2359 }
2360 }
2361 }
2362 }
2363
2364 /// When an APPLY transformer creates an aggregate function (e.g. `* APPLY x -> argMax(x, number)`
2365 /// or `* APPLY x -> toString(argMax(x, number))`), the matched columns must NOT be converted to
2366 /// Nullable here. Aggregate function arguments use pre-aggregation types (non-Nullable); the Nullable
2367 /// wrapping is handled post-aggregation by Rollup/Cube/GroupingSets transforms. Converting here would
2368 /// create a type mismatch: the aggregate function would expect Nullable input columns, but the actual
2369 /// columns in the Aggregating step are non-Nullable.
2370 /// This causes a crash in AggregateFunctionNullVariadic::addBatchSinglePlace.
2371 ///
2372 /// We traverse the APPLY expression tree because the aggregate function may be nested
2373 /// inside other function calls (e.g. `toString(argMax(x, number))`), not just at the top level.
2374 /// We use `AggregateFunctionFactory` name lookup (not `FunctionNode::isAggregateFunction`) because
2375 /// APPLY expressions have not been resolved yet at this point — `FunctionNode::kind` is still `UNKNOWN`.

Callers

nothing calls this directly

Calls 15

isQualifiedMethod · 0.80
getNodesMethod · 0.80
pushExpressionNodeMethod · 0.80
popExpressionNodeMethod · 0.80
isColumnMatchingMethod · 0.80
setOriginalASTMethod · 0.80
getNearestQueryScopeMethod · 0.80

Tested by

no test coverage detected