From 81cb803980b3f2723dbb6ada43a919776615a507 Mon Sep 17 00:00:00 2001 From: Deluan Date: Thu, 9 Jul 2026 13:07:15 -0400 Subject: [PATCH] refactor(scanner): query column nullability with a single-row pragma_table_info select Replace the manual PRAGMA table_info iteration in columnIsNotNull with a single-row query against the pragma_table_info table-valued function, binding both the table and column names. Note that the "notnull" result column must be quoted, as NOTNULL is an SQLite operator keyword. Suggested by review, with corrections for the keyword quoting and errorlint-compliant ErrNoRows check. --- ...0260709160132_fix_bpm_bitdepth_not_null.go | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/db/migrations/20260709160132_fix_bpm_bitdepth_not_null.go b/db/migrations/20260709160132_fix_bpm_bitdepth_not_null.go index 8b8afca2a..3cd28c5f0 100644 --- a/db/migrations/20260709160132_fix_bpm_bitdepth_not_null.go +++ b/db/migrations/20260709160132_fix_bpm_bitdepth_not_null.go @@ -3,7 +3,7 @@ package migrations import ( "context" "database/sql" - "fmt" + "errors" "github.com/navidrome/navidrome/log" "github.com/pressly/goose/v3" @@ -72,24 +72,16 @@ func downFixBpmBitdepthNotNull(ctx context.Context, tx *sql.Tx) error { } // columnIsNotNull reports whether the given column of the given table is declared -// with a NOT NULL constraint, using PRAGMA table_info. The table name is a fixed -// internal constant, so it is safe to interpolate (PRAGMA cannot bind parameters). +// with a NOT NULL constraint. "notnull" must be quoted: NOTNULL is an SQLite +// operator keyword. func columnIsNotNull(ctx context.Context, tx *sql.Tx, table, column string) (bool, error) { - rows, err := tx.QueryContext(ctx, fmt.Sprintf("PRAGMA table_info(%s)", table)) + var notNull int + err := tx.QueryRowContext(ctx, `SELECT "notnull" FROM pragma_table_info(?) WHERE name = ?`, table, column).Scan(¬Null) + if errors.Is(err, sql.ErrNoRows) { + return false, nil + } if err != nil { return false, err } - defer rows.Close() - for rows.Next() { - var cid, notnull, pk int - var name, ctype string - var dflt sql.NullString - if err = rows.Scan(&cid, &name, &ctype, ¬null, &dflt, &pk); err != nil { - return false, err - } - if name == column { - return notnull == 1, nil - } - } - return false, rows.Err() + return notNull == 1, nil }