From 7dfe003e6333822701122d2c488eab6435617a19 Mon Sep 17 00:00:00 2001 From: Caleb Allen Date: Wed, 4 Mar 2026 19:33:55 -0500 Subject: [PATCH] docs(06-03): add SAFETY comments to all 12 hand-crafted SQL statements - 7 SAFETY comments in search.go (FTS5 MATCH/INSERT/DELETE operations) - 3 SAFETY comments in library.go (FTS5 INSERT/DELETE in commitNewAudioFile, updateAudioFileMetadata) - 1 SAFETY comment in rescan.go (FTS5 DELETE in clearAllLibraryData) - 1 SAFETY comment in persistence.go (variable-count multi-row INSERT) - Cross-references link library.go/rescan.go back to search.go - Two-part format: why sqlc can't handle it + what makes it safe --- backend/database/search.go | 7 +++++++ backend/library/library.go | 3 +++ backend/library/rescan.go | 1 + backend/queue/persistence.go | 1 + 4 files changed, 12 insertions(+) diff --git a/backend/database/search.go b/backend/database/search.go index baa83c1..2b2193f 100644 --- a/backend/database/search.go +++ b/backend/database/search.go @@ -31,6 +31,7 @@ func (d *DB) SearchFTS( // special characters are treated as literals. ftsQuery := buildFTSQuery(query) + // SAFETY: FTS5 MATCH syntax unsupported by sqlc. Query is parameterized; no string interpolation. rows, err := d.db.QueryContext(d.Ctx, ` SELECT tm.file_path, @@ -77,6 +78,7 @@ func (d *DB) SearchFTSByFilename( ftsQuery := "file_path : " + strings.Join(tokens, " ") + // SAFETY: FTS5 MATCH syntax unsupported by sqlc. Query is parameterized; no string interpolation. rows, err := d.db.QueryContext(d.Ctx, ` SELECT tm.file_path, @@ -106,6 +108,7 @@ func (d *DB) InsertSearchIndex( rowid int64, filePath, title, artist, album string, ) error { + // SAFETY: FTS5 virtual table INSERT unsupported by sqlc. All values are parameterized. _, err := d.db.ExecContext(d.Ctx, ` INSERT INTO search_index(rowid, file_path, title, artist, album) VALUES (?, ?, ?, ?, ?) @@ -116,6 +119,7 @@ func (d *DB) InsertSearchIndex( // DeleteSearchIndex removes a row from the FTS5 search_index. func (d *DB) DeleteSearchIndex(rowid int64) error { + // SAFETY: FTS5 virtual table DELETE unsupported by sqlc. Rowid is parameterized. _, err := d.db.ExecContext(d.Ctx, ` DELETE FROM search_index WHERE rowid = ? `, rowid) @@ -125,6 +129,7 @@ func (d *DB) DeleteSearchIndex(rowid int64) error { // ClearSearchIndex removes all rows from the FTS5 search_index. func (d *DB) ClearSearchIndex() error { + // SAFETY: FTS5 virtual table DELETE unsupported by sqlc. No parameters; unconditional delete. _, err := d.db.ExecContext(d.Ctx, ` DELETE FROM search_index `) @@ -141,6 +146,7 @@ func (d *DB) RebuildSearchIndex() error { ) } + // SAFETY: FTS5 virtual table INSERT unsupported by sqlc. All values sourced from track_metadata VIEW; no user input. _, err := d.db.ExecContext(d.Ctx, ` INSERT INTO search_index(rowid, file_path, title, artist, album) SELECT id, file_path, title, artist_name, album @@ -189,6 +195,7 @@ func (d *DB) SearchFTSTracks( ftsQuery := buildFTSQuery(query) + // SAFETY: FTS5 MATCH syntax unsupported by sqlc. Query is parameterized; no string interpolation. rows, err := d.db.QueryContext(d.Ctx, ` SELECT tm.file_path, diff --git a/backend/library/library.go b/backend/library/library.go index 4f19927..1d7149b 100644 --- a/backend/library/library.go +++ b/backend/library/library.go @@ -793,6 +793,7 @@ func (l *Library) saveAudioFile( album := tags.Album + // SAFETY: FTS5 virtual table, see search.go:InsertSearchIndex. All values parameterized. if _, err := tx.ExecContext( l.ctx, `INSERT INTO search_index(rowid, file_path, title, artist, album) @@ -874,6 +875,7 @@ func (l *Library) updateAudioFileMetadata( album := tags.Album + // SAFETY: FTS5 virtual table, see search.go:DeleteSearchIndex. Rowid parameterized. if _, err := tx.ExecContext( l.ctx, `DELETE FROM search_index WHERE rowid = ?`, @@ -888,6 +890,7 @@ func (l *Library) updateAudioFileMetadata( metrics.addWarning(result.absolutePath, "commit", err) } + // SAFETY: FTS5 virtual table, see search.go:InsertSearchIndex. All values parameterized. if _, err := tx.ExecContext( l.ctx, `INSERT INTO search_index(rowid, file_path, title, artist, album) diff --git a/backend/library/rescan.go b/backend/library/rescan.go index 316d443..04594d5 100644 --- a/backend/library/rescan.go +++ b/backend/library/rescan.go @@ -161,6 +161,7 @@ func (l *Library) clearLibraryTables() error { } // Clear FTS5 search index. + // SAFETY: FTS5 virtual table, see search.go:ClearSearchIndex. No parameters; unconditional delete. if _, err := tx.ExecContext( l.ctx, `DELETE FROM search_index`, ); err != nil { diff --git a/backend/queue/persistence.go b/backend/queue/persistence.go index 42e3dc3..4a49a2b 100644 --- a/backend/queue/persistence.go +++ b/backend/queue/persistence.go @@ -151,6 +151,7 @@ func (q *Queue) insertTrackBatch(tx *sql.Tx, batch []Track) error { args = append(args, track.AudioFileID, track.Position) } + // SAFETY: Multi-row INSERT with variable row count unsupported by sqlc. Placeholder count matches args length; no string interpolation. query := "INSERT INTO queue_tracks (audio_file_id, position) VALUES " + strings.Join(valuePlaceholders, ",")