46 lines
2.5 KiB
Diff
46 lines
2.5 KiB
Diff
# UNDF: UNDF-2026-000000255
|
||
Fixes rails-0016: SQLite3Adapter#copy_table_indexes + copy_table_contents — to_column_names and from_columns are Arrays used inside .select and .find_all loops O(I×C×N).
|
||
|
||
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
|
||
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
|
||
|
||
@@ DEFECT rails-0016a: lines 705-730 copy_table_indexes
|
||
|
||
def copy_table_indexes(from, to, rename = {})
|
||
indexes(from).each do |index|
|
||
...
|
||
columns = index.columns
|
||
if columns.is_a?(Array)
|
||
- to_column_names = columns(to).map(&:name) # Array rebuilt per index
|
||
- columns = columns.map { |c| rename[c] || c }.select do |column|
|
||
- to_column_names.include?(column) # O(N) Array scan per column
|
||
+ to_column_names_set = columns(to).map(&:name).to_set # FIX: build Set once per index
|
||
+ columns = columns.map { |c| rename[c] || c }.select do |column|
|
||
+ to_column_names_set.include?(column) # O(1) per column
|
||
end
|
||
end
|
||
...
|
||
end
|
||
end
|
||
|
||
@@ DEFECT rails-0016b: lines 733-737 copy_table_contents
|
||
|
||
def copy_table_contents(from, to, columns, rename = {})
|
||
column_mappings = Hash[columns.map { |name| [name, name] }]
|
||
rename.each { |a| column_mappings[a.last] = a.first }
|
||
- from_columns = columns(from).collect(&:name) # Array
|
||
- columns = columns.find_all { |col| from_columns.include?(column_mappings[col]) } # O(C×N)
|
||
+ from_columns_set = columns(from).collect(&:name).to_set # FIX: Set for O(1) lookup
|
||
+ columns = columns.find_all { |col| from_columns_set.include?(column_mappings[col]) }
|
||
...
|
||
end
|
||
|
||
# BEFORE: copy_table_indexes: to_column_names is Array rebuilt for each index; include? O(N) per column
|
||
# I indexes × C columns per index × N columns per table = O(I×C×N)
|
||
# copy_table_contents: from_columns is Array; find_all with include? is O(C×N)
|
||
# AFTER: to_column_names_set / from_columns_set are Sets: O(1) include?
|
||
# copy_table_indexes: O(I×C); copy_table_contents: O(C)
|
||
# Severity: MEDIUM — hot during ALTER TABLE simulations (SQLite has no native ALTER)
|
||
# large tables with many indexes trigger this repeatedly
|
||
# Speedup: ~N× where N = column count
|
||
# At I=20 indexes, C=10 col/index, N=50 columns: 10,000 → 200 ops
|