Improve sqlite error messages

They did not include the detailed error message, losing essential
information for troubleshooting.

Example message:

    warning: creating statement 'insert or rplace into NARs(cache, hashPart, namePart, url, compression, fileHash, fileSize, narHash, narSize, refs, deriver, sigs, ca, timestamp, present) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1)': at offset 10: SQL logic error, near "rplace": syntax error (in '/tmp/nix-shell.grQ6f7/nix-test/tests/binary-cache/test-home/.cache/nix/binary-cache-v6.sqlite')

It's not the best example; more important information will be in
the message for e.g. a constraint violation.

I don't see why this specific error is printed as a warning, but
that's for another commit.
This commit is contained in:
Robert Hensing 2022-12-17 14:50:43 +01:00
parent 26c7602c39
commit c965f35de7
2 changed files with 16 additions and 10 deletions

View file

@ -8,12 +8,15 @@
namespace nix { namespace nix {
SQLiteError::SQLiteError(const char *path, int errNo, int extendedErrNo, hintformat && hf) SQLiteError::SQLiteError(const char *path, const char *errMsg, int errNo, int extendedErrNo, int offset, hintformat && hf)
: Error(""), path(path), errNo(errNo), extendedErrNo(extendedErrNo) : Error(""), path(path), errMsg(errMsg), errNo(errNo), extendedErrNo(extendedErrNo), offset(offset)
{ {
err.msg = hintfmt("%s: %s (in '%s')", auto offsetStr = (offset == -1) ? "" : "at offset " + std::to_string(offset) + ": ";
err.msg = hintfmt("%s: %s%s, %s (in '%s')",
normaltxt(hf.str()), normaltxt(hf.str()),
offsetStr,
sqlite3_errstr(extendedErrNo), sqlite3_errstr(extendedErrNo),
errMsg,
path ? path : "(in-memory)"); path ? path : "(in-memory)");
} }
@ -21,11 +24,13 @@ SQLiteError::SQLiteError(const char *path, int errNo, int extendedErrNo, hintfor
{ {
int err = sqlite3_errcode(db); int err = sqlite3_errcode(db);
int exterr = sqlite3_extended_errcode(db); int exterr = sqlite3_extended_errcode(db);
int offset = sqlite3_error_offset(db);
auto path = sqlite3_db_filename(db, nullptr); auto path = sqlite3_db_filename(db, nullptr);
auto errMsg = sqlite3_errmsg(db);
if (err == SQLITE_BUSY || err == SQLITE_PROTOCOL) { if (err == SQLITE_BUSY || err == SQLITE_PROTOCOL) {
auto exp = SQLiteBusy(path, err, exterr, std::move(hf)); auto exp = SQLiteBusy(path, errMsg, err, exterr, offset, std::move(hf));
exp.err.msg = hintfmt( exp.err.msg = hintfmt(
err == SQLITE_PROTOCOL err == SQLITE_PROTOCOL
? "SQLite database '%s' is busy (SQLITE_PROTOCOL)" ? "SQLite database '%s' is busy (SQLITE_PROTOCOL)"
@ -33,7 +38,7 @@ SQLiteError::SQLiteError(const char *path, int errNo, int extendedErrNo, hintfor
path ? path : "(in-memory)"); path ? path : "(in-memory)");
throw exp; throw exp;
} else } else
throw SQLiteError(path, err, exterr, std::move(hf)); throw SQLiteError(path, errMsg, err, exterr, offset, std::move(hf));
} }
SQLite::SQLite(const Path & path, bool create) SQLite::SQLite(const Path & path, bool create)

View file

@ -98,21 +98,22 @@ struct SQLiteTxn
struct SQLiteError : Error struct SQLiteError : Error
{ {
const char *path; std::string path;
int errNo, extendedErrNo; std::string errMsg;
int errNo, extendedErrNo, offset;
template<typename... Args> template<typename... Args>
[[noreturn]] static void throw_(sqlite3 * db, const std::string & fs, const Args & ... args) { [[noreturn]] static void throw_(sqlite3 * db, const std::string & fs, const Args & ... args) {
throw_(db, hintfmt(fs, args...)); throw_(db, hintfmt(fs, args...));
} }
SQLiteError(const char *path, int errNo, int extendedErrNo, hintformat && hf); SQLiteError(const char *path, const char *errMsg, int errNo, int extendedErrNo, int offset, hintformat && hf);
protected: protected:
template<typename... Args> template<typename... Args>
SQLiteError(const char *path, int errNo, int extendedErrNo, const std::string & fs, const Args & ... args) SQLiteError(const char *path, const char *errMsg, int errNo, int extendedErrNo, int offset, const std::string & fs, const Args & ... args)
: SQLiteError(path, errNo, extendedErrNo, hintfmt(fs, args...)) : SQLiteError(path, errNo, extendedErrNo, offset, hintfmt(fs, args...))
{ } { }
[[noreturn]] static void throw_(sqlite3 * db, hintformat && hf); [[noreturn]] static void throw_(sqlite3 * db, hintformat && hf);