Resolve GROUP BY clause. */
| 3875 | /** Resolve GROUP BY clause. |
| 3876 | */ |
| 3877 | void QueryAnalyzer::resolveGroupByNode(QueryNode & query_node_typed, IdentifierResolveScope & scope) |
| 3878 | { |
| 3879 | QueryTreeNodes nullable_group_by_keys; |
| 3880 | |
| 3881 | if (query_node_typed.isGroupByWithGroupingSets()) |
| 3882 | { |
| 3883 | for (auto & grouping_sets_keys_list_node : query_node_typed.getGroupBy().getNodes()) |
| 3884 | { |
| 3885 | replaceNodesWithPositionalArguments(grouping_sets_keys_list_node, query_node_typed.getProjection().getNodes(), scope); |
| 3886 | |
| 3887 | resolveExpressionNodeList(grouping_sets_keys_list_node, scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); |
| 3888 | |
| 3889 | // Remove redundant calls to `tuple` function. It simplifies checking if expression is an aggregation key. |
| 3890 | // It's required to support queries like: SELECT number FROM numbers(3) GROUP BY (number, number % 2) |
| 3891 | auto & group_by_list = grouping_sets_keys_list_node->as<ListNode &>().getNodes(); |
| 3892 | expandTuplesInList(group_by_list); |
| 3893 | } |
| 3894 | |
| 3895 | for (const auto & grouping_set : query_node_typed.getGroupBy().getNodes()) |
| 3896 | { |
| 3897 | for (const auto & group_by_elem : grouping_set->as<ListNode>()->getNodes()) |
| 3898 | { |
| 3899 | validateGroupByKeyType(group_by_elem->getResultType(), scope); |
| 3900 | if (scope.group_by_use_nulls) |
| 3901 | nullable_group_by_keys.push_back(group_by_elem); |
| 3902 | } |
| 3903 | } |
| 3904 | } |
| 3905 | else |
| 3906 | { |
| 3907 | replaceNodesWithPositionalArguments(query_node_typed.getGroupByNode(), query_node_typed.getProjection().getNodes(), scope); |
| 3908 | |
| 3909 | resolveExpressionNodeList(query_node_typed.getGroupByNode(), scope, false /*allow_lambda_expression*/, false /*allow_table_expression*/); |
| 3910 | |
| 3911 | // Remove redundant calls to `tuple` function. It simplifies checking if expression is an aggregation key. |
| 3912 | // It's required to support queries like: SELECT number FROM numbers(3) GROUP BY (number, number % 2) |
| 3913 | auto & group_by_list = query_node_typed.getGroupBy().getNodes(); |
| 3914 | expandTuplesInList(group_by_list); |
| 3915 | |
| 3916 | for (const auto & group_by_elem : query_node_typed.getGroupBy().getNodes()) |
| 3917 | { |
| 3918 | validateGroupByKeyType(group_by_elem->getResultType(), scope); |
| 3919 | if (scope.group_by_use_nulls) |
| 3920 | nullable_group_by_keys.push_back(group_by_elem); |
| 3921 | } |
| 3922 | } |
| 3923 | |
| 3924 | if (!nullable_group_by_keys.empty()) |
| 3925 | registerNullableGroupByKeys(nullable_group_by_keys, scope); |
| 3926 | |
| 3927 | /// With group_by_use_nulls the projection (and the other clauses) are re-resolved after GROUP BY |
| 3928 | /// so that expressions equal to a key become Nullable via the scope.nullable_group_by_keys |
| 3929 | /// lookup. Clear the resolution caches so that this re-resolution actually re-runs instead of |
| 3930 | /// reusing the non-Nullable results cached during the first resolution. |
| 3931 | if (!scope.nullable_group_by_keys.empty()) |
| 3932 | { |
| 3933 | resolved_expressions.clear(); |
| 3934 | scope.clearIdentifierCache(); |
nothing calls this directly
no test coverage detected