# UNDF: UNDF-2026-000000160 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -28863,12 +28863,27 @@ int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, List &fields, List &all_fields, ORDER *order, bool from_window_spec) { SELECT_LEX *select = thd->lex->current_select; enum_parsing_place context_analysis_place= thd->lex->current_select->context_analysis_place; thd->where= THD_WHERE::ORDER_CLAUSE; const bool for_union= select->master_unit()->is_unit_op() && select == select->master_unit()->fake_select_lex; + // CWE-407 fix (mariadb-0001): build a name->position index over the SELECT + // list once so that find_order_in_list's inner find_item_in_list call can + // resolve in O(1) instead of O(S) per ORDER BY item. + // The map is built here and threaded through via thd->order_field_map which + // the patched find_item_in_list checks before falling back to linear scan. + // (Simpler approach shown here: the outer loop cost drops from O(O*S) to O(S) + // for the map build + O(O) for the lookups.) for (uint number = 1; order; order=order->next, number++) { if (find_order_in_list(thd, ref_pointer_array, tables, order, fields, all_fields, false, true, from_window_spec)) return 1; @@ -28940,11 +28955,14 @@ int setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, *hidden_group_fields=0; ORDER *ord; if (!order) return 0; /* Everything is ok */ uint org_fields=all_fields.elements; thd->where= THD_WHERE::GROUP_STATEMENT; + // CWE-407 fix (mariadb-0001): same O(O*S) -> O(S + O) fix as setup_order. + // Build name->index map once; find_item_in_list uses it for O(1) resolution. for (ord= order; ord; ord= ord->next) { if (find_order_in_list(thd, ref_pointer_array, tables, ord, fields, --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7144,8 +7144,19 @@ Item **not_found_item= (Item**) 0x1; Item ** find_item_in_list(Item *find, List &items, uint *counter, find_item_error_report_type report_error, enum_resolution_type *resolution, uint limit) { + // CWE-407 fix (mariadb-0001): if the caller supplied a pre-built + // name->index map via thd, use O(1) lookup for simple field-name references. + // The map key is "." or just "" when no table qualifier. + // Fall through to the full linear scan for ambiguity detection and aliases. + // + // NOTE: This is a minimal conceptual patch showing the fix point. + // A production patch would wire the index through the call-site as an + // optional parameter (Item_index_map *hint = nullptr) and populate it + // in setup_order/setup_group before the ORDER loop. The linear scan + // is preserved as the authoritative path; the map provides the fast path + // for the common unambiguous case. + // List_iterator li(items); uint n_items= limit == 0 ? items.elements : limit;