perf(rtl): SORT TO swaps insertion sort for sort.SliceStable (Wave 4)

Drop the toy O(n²) insertion-sort that __dbSort had been using and
delegate to the stdlib's sort.SliceStable. Reasoning: SORT TO is an
operation a user reaches for *because* their dataset is too big to
just iterate manually — interactive DBFs routinely have 10k–1M rows,
which the old impl would chew on for minutes to hours. SliceStable
gives O(n log n) and preserves the original-input ordering for
equal keys, which is what the previous implementation also tried to
do.

The function signature is unchanged (`stableSort(rows, less)`), so
all the multi-key / /D / /C dispatch logic from earlier waves keeps
working unmodified.

Gates green:
  go test ./...      : PASS
  FiveSql2 SQL:1999  : 43/43
  Harbour compat     : 56/56

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-01 08:03:13 +09:00
parent 5b1d3fb32f
commit 1a9e509ee2

View File

@@ -10,6 +10,7 @@ package hbrtl
import ( import (
"fmt" "fmt"
"os" "os"
"sort"
"strings" "strings"
"five/hbrt" "five/hbrt"
@@ -1914,14 +1915,12 @@ func rtlDbUpdate(t *hbrt.Thread) {
t.RetBool(true) t.RetBool(true)
} }
// stableSort is a tiny insertion sort for small N (typical DBF SORT // stableSort sorts rows in place via the stdlib's `sort.SliceStable`
// targets are interactive datasets). Avoids a sort import dependency. // — O(n log n) with stable ordering preserved for equal keys. The
// previous insertion-sort implementation degraded to O(n²) and was
// unusable for DBFs over a few thousand rows.
func stableSort(rows [][]hbrt.Value, less func(i, j int) bool) { func stableSort(rows [][]hbrt.Value, less func(i, j int) bool) {
for i := 1; i < len(rows); i++ { sort.SliceStable(rows, less)
for j := i; j > 0 && less(j, j-1); j-- {
rows[j], rows[j-1] = rows[j-1], rows[j]
}
}
} }
// --- DBSETFILTER / DBCLEARFILTER / DBFILTER --- // --- DBSETFILTER / DBCLEARFILTER / DBFILTER ---