From 1f0b756378a2b5cfe09b5a496e14df274688b541 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Wed, 29 Jul 2026 08:57:25 +0900 Subject: [PATCH 1/2] Do not clobber SQLite's default cost estimates in BestIndex --- sqlite3_opt_vtable.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/sqlite3_opt_vtable.go b/sqlite3_opt_vtable.go index 9e916ea..33de0dc 100644 --- a/sqlite3_opt_vtable.go +++ b/sqlite3_opt_vtable.go @@ -482,8 +482,22 @@ func goVBestIndex(pVTab unsafe.Pointer, icp unsafe.Pointer) *C.char { if res.AlreadyOrdered { info.orderByConsumed = C.int(1) } - info.estimatedCost = C.double(res.EstimatedCost) - info.estimatedRows = C.sqlite3_int64(res.EstimatedRows) + // SQLite pre-initializes estimatedCost and estimatedRows with sensible + // defaults; overwriting them with the Go zero value would make every + // candidate plan look free and break query planning, so only pass + // values the implementation actually set. + if res.EstimatedCost > 0 { + info.estimatedCost = C.double(res.EstimatedCost) + } + if res.EstimatedRows > 0 { + var rows int64 + if res.EstimatedRows >= float64(math.MaxInt64) { + rows = math.MaxInt64 + } else { + rows = int64(res.EstimatedRows) + } + info.estimatedRows = C.sqlite3_int64(rows) + } return nil } From 2897b83d1848f1a9b191b125a6c614de9bba7efb Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Wed, 29 Jul 2026 11:10:45 +0900 Subject: [PATCH 2/2] Clamp fractional row estimates to at least 1 --- sqlite3_opt_vtable.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sqlite3_opt_vtable.go b/sqlite3_opt_vtable.go index 33de0dc..aded1b4 100644 --- a/sqlite3_opt_vtable.go +++ b/sqlite3_opt_vtable.go @@ -493,8 +493,9 @@ func goVBestIndex(pVTab unsafe.Pointer, icp unsafe.Pointer) *C.char { var rows int64 if res.EstimatedRows >= float64(math.MaxInt64) { rows = math.MaxInt64 - } else { - rows = int64(res.EstimatedRows) + } else if rows = int64(res.EstimatedRows); rows < 1 { + // A positive fractional estimate must not truncate to 0. + rows = 1 } info.estimatedRows = C.sqlite3_int64(rows) }