From c86e34a01d10da80db2af774bcc75410c43402e0 Mon Sep 17 00:00:00 2001 From: didier amyot Date: Fri, 5 Jun 2026 16:09:46 -0400 Subject: [PATCH] fix: materialize FTS hits before fetching entries to avoid sqlite deadlock --- sqlite.go | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/sqlite.go b/sqlite.go index cce8ee9..b9eb7d0 100644 --- a/sqlite.go +++ b/sqlite.go @@ -218,16 +218,29 @@ func (s *sqliteStore) searchFTS(ctx context.Context, query string, limit uint64) if err != nil { return nil, fmt.Errorf("fts query: %w", err) } - defer rows.Close() - var results []searchResult + type hit struct { + id int64 + rank float64 + } + var hits []hit for rows.Next() { - var id int64 - var rank float64 - if err := rows.Scan(&id, &rank); err != nil { + var h hit + if err := rows.Scan(&h.id, &h.rank); err != nil { + rows.Close() return nil, fmt.Errorf("scan: %w", err) } - entry, err := s.getByID(ctx, id) + hits = append(hits, h) + } + rows.Close() + + if err := rows.Err(); err != nil { + return nil, fmt.Errorf("rows: %w", err) + } + + results := make([]searchResult, 0, len(hits)) + for _, h := range hits { + entry, err := s.getByID(ctx, h.id) if err != nil { return nil, fmt.Errorf("get entry: %w", err) } @@ -236,12 +249,9 @@ func (s *sqliteStore) searchFTS(ctx context.Context, query string, limit uint64) } results = append(results, searchResult{ Entry: *entry, - Score: float32(-rank), + Score: float32(-h.rank), }) } - if err := rows.Err(); err != nil { - return nil, fmt.Errorf("rows: %w", err) - } return results, nil }