| 1189 | } |
| 1190 | |
| 1191 | PlannerActionsVisitorImpl::NodeNameAndNodeMinLevel PlannerActionsVisitorImpl::visitFunction(const QueryTreeNodePtr & node) |
| 1192 | { |
| 1193 | const auto & function_node = node->as<FunctionNode &>(); |
| 1194 | |
| 1195 | if (function_node.getFunctionName() == "indexHint") |
| 1196 | return visitIndexHintFunction(node); |
| 1197 | if (function_node.getFunctionName() == "exists") |
| 1198 | return visitExistsFunction(node); |
| 1199 | |
| 1200 | std::optional<NodeNameAndNodeMinLevel> in_function_second_argument_node_name_with_level; |
| 1201 | |
| 1202 | if (isNameOfInFunction(function_node.getFunctionName())) |
| 1203 | in_function_second_argument_node_name_with_level = makeSetForInFunction(node); |
| 1204 | |
| 1205 | auto function_node_name = action_node_name_helper.calculateActionNodeName(node); |
| 1206 | |
| 1207 | /* Aggregate functions, window functions, and GROUP BY expressions were already analyzed in the previous steps. |
| 1208 | * If we have already visited some expression, we don't need to revisit it or its arguments again. |
| 1209 | * For example, the expression from the aggregation step is also present in the projection: |
| 1210 | * SELECT foo(a, b, c) as x FROM table GROUP BY foo(a, b, c) |
| 1211 | * In this case we should not analyze `a`, `b`, `c` again. |
| 1212 | * Moreover, it can lead to an error if we have arrayJoin in the arguments because it will be calculated twice. |
| 1213 | * |
| 1214 | * The expression can also be present as a constant COLUMN node: when a GROUP BY key expression |
| 1215 | * is constant-foldable, the aggregation step exposes it as a constant column, and the ActionsDAG |
| 1216 | * constructor duplicates constant inputs as COLUMN nodes. Visiting the arguments in this case can |
| 1217 | * lead to an error: for example, after aggregation with group_by_use_nulls, GROUP BY key constants |
| 1218 | * are wrapped into Nullable but keep their names, and a lambda capture built over such a constant |
| 1219 | * fails with a type mismatch. |
| 1220 | */ |
| 1221 | bool is_input_node = function_node.isAggregateFunction() || function_node.isWindowFunction() |
| 1222 | || actions_stack.front().containsInputOrConstantNode(function_node_name); |
| 1223 | if (is_input_node) |
| 1224 | { |
| 1225 | size_t actions_stack_size = actions_stack.size(); |
| 1226 | |
| 1227 | for (size_t i = 0; i < actions_stack_size; ++i) |
| 1228 | { |
| 1229 | auto & actions_stack_node = actions_stack[i]; |
| 1230 | actions_stack_node.addInputColumnIfNecessary(function_node_name, function_node.getResultType()); |
| 1231 | } |
| 1232 | |
| 1233 | return {function_node_name, Levels(0)}; |
| 1234 | } |
| 1235 | |
| 1236 | const auto & function_arguments = function_node.getArguments().getNodes(); |
| 1237 | size_t function_arguments_size = function_arguments.size(); |
| 1238 | |
| 1239 | Names function_arguments_node_names; |
| 1240 | function_arguments_node_names.reserve(function_arguments_size); |
| 1241 | |
| 1242 | Levels levels(0); |
| 1243 | for (size_t function_argument_index = 0; function_argument_index < function_arguments_size; ++function_argument_index) |
| 1244 | { |
| 1245 | if (in_function_second_argument_node_name_with_level && function_argument_index == 1) |
| 1246 | { |
| 1247 | auto & [node_name, node_levels] = *in_function_second_argument_node_name_with_level; |
| 1248 | function_arguments_node_names.push_back(std::move(node_name)); |
nothing calls this directly
no test coverage detected