| 1515 | } |
| 1516 | |
| 1517 | std::optional<std::pair<JoinStepLogical::ActionsDAGWithKeys, JoinStepLogical::ActionsDAGWithKeys>> |
| 1518 | JoinStepLogical::preCalculateKeys(const SharedHeader & left_header, const SharedHeader & right_header) |
| 1519 | { |
| 1520 | auto & join_expression = join_operator.expression; |
| 1521 | |
| 1522 | ActionsDAG::NodeRawConstPtrs left_keys; |
| 1523 | ActionsDAG::NodeRawConstPtrs right_keys; |
| 1524 | |
| 1525 | for (auto & expr : join_expression) |
| 1526 | { |
| 1527 | auto [predicate_op, lhs, rhs] = expr.asBinaryPredicate(); |
| 1528 | if (predicate_op != JoinConditionOperator::Equals) |
| 1529 | continue; |
| 1530 | |
| 1531 | const auto * left_node = lhs.getNode(); |
| 1532 | const auto * right_node = rhs.getNode(); |
| 1533 | if (lhs.fromLeft() && rhs.fromRight()) |
| 1534 | { |
| 1535 | left_keys.push_back(left_node); |
| 1536 | right_keys.push_back(right_node); |
| 1537 | } |
| 1538 | else if (lhs.fromRight() && rhs.fromLeft()) |
| 1539 | { |
| 1540 | left_keys.push_back(right_node); |
| 1541 | right_keys.push_back(left_node); |
| 1542 | } |
| 1543 | else |
| 1544 | { |
| 1545 | continue; |
| 1546 | } |
| 1547 | |
| 1548 | /// Replace keys expression with calculated inputs |
| 1549 | /// We also could possibly remove some nodes from dag, |
| 1550 | /// but they will simply remain unused when converting to a physical step |
| 1551 | if (left_node->type != ActionsDAG::ActionType::INPUT || |
| 1552 | right_node->type != ActionsDAG::ActionType::INPUT) |
| 1553 | { |
| 1554 | if (left_node->type != ActionsDAG::ActionType::INPUT) |
| 1555 | lhs = expression_actions.addInput(left_node->result_name, left_node->result_type, lhs.fromLeft() ? 0 : 1); |
| 1556 | if (right_node->type != ActionsDAG::ActionType::INPUT) |
| 1557 | rhs = expression_actions.addInput(right_node->result_name, right_node->result_type, rhs.fromRight() ? 1 : 0); |
| 1558 | expr = JoinActionRef::transform({lhs, rhs}, JoinActionRef::AddFunction(predicate_op)); |
| 1559 | } |
| 1560 | } |
| 1561 | |
| 1562 | if (left_keys.empty() || right_keys.empty()) |
| 1563 | return {}; |
| 1564 | |
| 1565 | auto left_dag = cloneSubdagWithInputs(left_header, left_keys); |
| 1566 | updateInputHeader(std::make_shared<Block>(left_dag.getResultColumns()), 0); |
| 1567 | |
| 1568 | auto right_dag = cloneSubdagWithInputs(right_header, right_keys); |
| 1569 | updateInputHeader(std::make_shared<Block>(right_dag.getResultColumns()), 1); |
| 1570 | |
| 1571 | return std::make_optional(std::pair{ |
| 1572 | ActionsDAGWithKeys{std::move(left_dag), std::move(left_keys)}, |
| 1573 | ActionsDAGWithKeys{std::move(right_dag), std::move(right_keys)}, |
| 1574 | }); |
no test coverage detected