java-topology/defects/mysql/patch/mysql-0003-setup-fields-find.md

1.8 KiB

UNDF: UNDF-2026-000000177

mysql-0003 — setup_fields(): O(F²) std::find iterator recovery inside item loop

Status

PATCHED

Severity

MEDIUM (conditional path — only triggers when split_sum_func fires; bounded in practice to aggregate-heavy queries with wide SELECT lists)

Location

sql/sql_base.cc, function setup_fields(), line ~9496

Description

setup_fields iterates over the fields deque (size F) to fix and resolve each Item. After calling item->split_sum_func(...), the deque may grow (new items appended), invalidating the range-based iterator it. The current recovery code is:

if (old_size != fields->size()) {
    it = std::find(fields->begin(), fields->end(), item);
}

std::find performs an O(F) linear scan to rediscover the current item's position. In a query with F columns where every column has an aggregate that triggers split_sum_func, this recovery fires F times, each scanning O(F) elements — O(F²) total.

Fix

Replace the std::find recovery with an index-based approach: replace the range-for with an explicit index loop. After split_sum_func fires, the new items are always appended to the end, so the current item's physical position is unchanged — we only need to update the end sentinel. With an index loop, no re-scan is necessary.

// Replace:
for (auto it = fields->begin(); it != fields->end(); ++it) {
    ...
    if (old_size != fields->size()) {
        it = std::find(fields->begin(), fields->end(), item);  // O(F)
    }
}

// With:
for (size_t idx = 0; idx < fields->size(); ++idx) {
    Item *item = (*fields)[idx];
    // split_sum_func may append to fields; idx stays valid because
    // mem_root_deque is stable for existing indices after push_back.
    // No re-scan needed.
}

Patch file

See mysql-0003-setup-fields-find.patch