Repository: ClickHouse/ClickHouse
File: src/Processors/QueryPlan/Optimizations/filterPushDown.cpp (C++)

Code before:
    if (auto split_filter = splitFilter(parent_node, step_changes_the_number_of_rows, allowed_inputs, child_idx))
        return addNewFilterStepOrThrow(parent_node, nodes, std::move(*split_filter), child_idx);
    return 0;
}


/// Push down filter through specified type of step
template <typename Step>
static size_t simplePushDownOverStep(QueryPlan::Node * parent_node, bool step_changes_the_number_of_rows, QueryPlan::Nodes & nodes, QueryPlanStepPtr & child)
{
    if (typeid_cast<Step *>(child.get()))
    {
        Names allowed_inputs = child->getOutputHeader()->getNames();
        if (auto updated_steps = tryAddNewFilterStep(parent_node, step_changes_the_number_of_rows, nodes, allowed_inputs))
            return updated_steps;
    }
    return 0;
}

static void buildEquialentSetsForJoinStepLogical(
    std::vector<std::pair<JoinActionRef, JoinActionRef>> & equivalent_expressions,
    const JoinOperator & join_operator)
{
    for (const auto & predicate : join_operator.expression)
    {
        auto [predicate_op, lhs, rhs] = predicate.asBinaryPredicate();
        if (predicate_op != JoinConditionOperator::Equals && predicate_op != JoinConditionOperator::NullSafeEquals)
            continue;

        if (lhs.fromRight() && rhs.fromLeft())
            std::swap(lhs, rhs);
        else if (!lhs.fromLeft() || !rhs.fromRight())
            continue;

        auto left_column = lhs.getColumn();
        auto right_column = rhs.getColumn();
        if (!left_column.type->equals(*right_column.type))
            continue;
        equivalent_expressions.emplace_back(lhs, rhs);
    }
}

static void projectDagInputs(ActionsDAG & actions_dag)
{
    auto & outputs = actions_dag.getOutputs();
    auto existing_outputs = std::ranges::to<std::unordered_set>(outputs);

    for (const auto * node : actions_dag.getInputs())
    {
        if (existing_outputs.contains(node))
            continue;

Review comment (suggestion):
I find it misleading that this function is called find but it actually modifies the data structure. I think it might worth to rename to "findOrInsert" or something like that.

Code after:
    if (auto split_filter = splitFilter(parent_node, step_changes_the_number_of_rows, allowed_inputs, child_idx))
        return addNewFilterStepOrThrow(parent_node, nodes, std::move(*split_filter), child_idx);
    return 0;
}


/// Push down filter through specified type of step
template <typename Step>
static size_t simplePushDownOverStep(QueryPlan::Node * parent_node, bool step_changes_the_number_of_rows, QueryPlan::Nodes & nodes, QueryPlanStepPtr & child)
{
    if (typeid_cast<Step *>(child.get()))
    {
        Names allowed_inputs = child->getOutputHeader()->getNames();
        if (auto updated_steps = tryAddNewFilterStep(parent_node, step_changes_the_number_of_rows, nodes, allowed_inputs))
            return updated_steps;
    }
    return 0;
}

/// Disjoint Set Union (Union-Find) data structure for JoinActionRef.
/// Used to find equivalent expressions in JOIN conditions.
/// For example, if (a = b) and (b = c), then a, b, c belong to the same equivalence class.
class EquivalentJoinKeySet
{
public:
    JoinActionRef find(JoinActionRef ref)
    {
        auto it = parent.find(ref);
        if (it == parent.end())
        {
            parent.emplace(ref, ref);
            return ref;
        }

        if (it->second == ref)
            return ref;

        JoinActionRef root = find(it->second);
        parent.insert_or_assign(ref, root);
        return root;
    }

    JoinActionRef unite(JoinActionRef a, JoinActionRef b)
    {
        JoinActionRef root_a = find(a);
        JoinActionRef root_b = find(b);

        if (root_a == root_b)
            return root_a;

        size_t rank_a = rank[root_a];