| 395 | } |
| 396 | |
| 397 | JoinStepLogical::RemoveUnusedColumnsResult JoinStepLogical::removeUnusedColumns(const std::vector<size_t> & required_output_positions, bool remove_inputs) |
| 398 | { |
| 399 | auto & actions_dag = *expression_actions.getActionsDAG(); |
| 400 | const size_t original_input_count = actions_dag.getInputs().size(); |
| 401 | ActionsDAG::NodeRawConstPtrs required_nodes; |
| 402 | ActionsDAG::NodeRawConstPtrs new_actions_after_join = actions_after_join; |
| 403 | |
| 404 | /// For JoinStepLogical, the output header maps directly to DAG outputs (no pass-throughs). |
| 405 | /// Build a set of required DAG output positions. |
| 406 | std::set<size_t> required_positions_set(required_output_positions.begin(), required_output_positions.end()); |
| 407 | |
| 408 | /// Track which original output positions survive (required + non-removable like dummy). |
| 409 | std::vector<size_t> kept_output_positions; |
| 410 | kept_output_positions.reserve(required_output_positions.size()); |
| 411 | |
| 412 | bool removed_any_output = false; |
| 413 | const auto & dag_outputs = actions_dag.getOutputs(); |
| 414 | for (size_t i = 0; i < dag_outputs.size(); ++i) |
| 415 | { |
| 416 | const auto * output_node = dag_outputs[i]; |
| 417 | if (required_positions_set.contains(i)) |
| 418 | { |
| 419 | required_nodes.push_back(output_node); |
| 420 | kept_output_positions.push_back(i); |
| 421 | } |
| 422 | else if (!isDummyColumnOfThisStep(output_node)) |
| 423 | { |
| 424 | /// Do not remove join_dummy_result from the outputs, because it was added to ensure at least one output column |
| 425 | removed_any_output = true; |
| 426 | new_actions_after_join.erase( |
| 427 | std::remove(new_actions_after_join.begin(), new_actions_after_join.end(), output_node), new_actions_after_join.end()); |
| 428 | } |
| 429 | else |
| 430 | { |
| 431 | /// Dummy column kept even though not required. |
| 432 | required_nodes.push_back(output_node); |
| 433 | kept_output_positions.push_back(i); |
| 434 | } |
| 435 | } |
| 436 | |
| 437 | if (required_nodes.empty()) |
| 438 | { |
| 439 | auto column_type = std::make_shared<DataTypeUInt8>(); |
| 440 | auto column = column_type->createColumnConst(0, 0); |
| 441 | const auto * node = &actions_dag.addColumn(std::move(column), column_type, String(join_dummy_result_name)); |
| 442 | new_actions_after_join.push_back(node); |
| 443 | required_nodes.push_back(node); |
| 444 | actions_dag.getOutputs().push_back(node); |
| 445 | kept_output_positions.push_back(RemoveUnusedColumnsResult::NEWLY_ADDED_COLUMN_POSITION); |
| 446 | } |
| 447 | |
| 448 | ActionsDAG::NodeRawConstPtrs new_outputs = required_nodes; |
| 449 | |
| 450 | for (const auto & join_action : join_operator.expression) |
| 451 | required_nodes.push_back(join_action.getNode()); |
| 452 | |
| 453 | for (const auto & join_action : join_operator.residual_filter) |
| 454 | required_nodes.push_back(join_action.getNode()); |
nothing calls this directly
no test coverage detected