diff --git a/src/DBConnection.cpp b/src/DBConnection.cpp index 6a19d29b2..ca6229329 100644 --- a/src/DBConnection.cpp +++ b/src/DBConnection.cpp @@ -22,6 +22,7 @@ Paul Licameli -- split from ProjectFileIO.cpp #include "Project.h" #include "FileException.h" #include "wxFileNameWrapper.h" +#include "SentryHelper.h" // Configuration to provide "safe" connections static const char *SafeConfig = @@ -162,7 +163,11 @@ int DBConnection::OpenStepByStep(const FilePath fileName) bool success = false; int rc = sqlite3_open(name, &mDB); - if (rc != SQLITE_OK) { + if (rc != SQLITE_OK) + { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "DBConnection::OpenStepByStep::open"); + wxLogMessage("Failed to open primary connection to %s: %d, %s\n", fileName, rc, @@ -173,13 +178,18 @@ int DBConnection::OpenStepByStep(const FilePath fileName) // Set default mode // (See comments in ProjectFileIO::SaveProject() about threading rc = SafeMode(); - if (rc != SQLITE_OK) { + if (rc != SQLITE_OK) + { SetDBError(XO("Failed to set safe mode on primary connection to %s").Format(fileName)); return rc; } rc = sqlite3_open(name, &mCheckpointDB); - if (rc != SQLITE_OK) { + if (rc != SQLITE_OK) + { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "DBConnection::OpenStepByStep::open_checkpoint"); + wxLogMessage("Failed to open checkpoint connection to %s: %d, %s\n", fileName, rc, @@ -283,6 +293,9 @@ bool DBConnection::Close() rc = sqlite3_close(mCheckpointDB); if (rc != SQLITE_OK) { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "DBConnection::Close::close_checkpoint"); + wxLogMessage("Failed to close checkpoint connection for %s\n" "\tError: %s\n", sqlite3_db_filename(mCheckpointDB, nullptr), @@ -294,6 +307,9 @@ bool DBConnection::Close() rc = sqlite3_close(mDB); if (rc != SQLITE_OK) { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "DBConnection::OpenStepByStep::close"); + wxLogMessage("Failed to close %s\n" "\tError: %s\n", sqlite3_db_filename(mDB, nullptr), @@ -341,6 +357,10 @@ int DBConnection::ModeConfig(sqlite3 *db, const char *schema, const char *config rc = sqlite3_exec(db, sql, nullptr, nullptr, nullptr); if (rc != SQLITE_OK) { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "DBConnection::ModeConfig"); + ADD_EXCEPTION_CONTEXT("sqlite3.mode", config); + // Don't store in connection, just report it wxLogMessage("Failed to set mode on %s\n" "\tError: %s\n" @@ -392,6 +412,10 @@ sqlite3_stmt *DBConnection::Prepare(enum StatementID id, const char *sql) rc = sqlite3_prepare_v3(mDB, sql, -1, SQLITE_PREPARE_PERSISTENT, &stmt, 0); if (rc != SQLITE_OK) { + ADD_EXCEPTION_CONTEXT("sqlite3.query", sql); + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "DBConnection::Prepare"); + wxLogMessage("Failed to prepare statement for %s\n" "\tError: %s\n" "\tSQL: %s", @@ -465,6 +489,9 @@ void DBConnection::CheckpointThread(sqlite3 *db, const FilePath &fileName) if (rc != SQLITE_OK) { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "DBConnection::CheckpointThread"); + wxLogMessage("Failed to perform checkpoint on %s\n" "\tErrCode: %d\n" "\tErrMsg: %s", @@ -537,6 +564,9 @@ bool TransactionScope::TransactionStart(const wxString &name) if (errmsg) { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "TransactionScope::TransactionStart"); + mConnection.SetDBError( XO("Failed to create savepoint:\n\n%s").Format(name) ); @@ -558,6 +588,9 @@ bool TransactionScope::TransactionCommit(const wxString &name) if (errmsg) { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "TransactionScope::TransactionCommit"); + mConnection.SetDBError( XO("Failed to release savepoint:\n\n%s").Format(name) ); @@ -579,6 +612,9 @@ bool TransactionScope::TransactionRollback(const wxString &name) if (errmsg) { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "TransactionScope::TransactionRollback"); + mConnection.SetDBError( XO("Failed to release savepoint:\n\n%s").Format(name) ); diff --git a/src/ProjectFileIO.cpp b/src/ProjectFileIO.cpp index 6028af4a4..07c15ee10 100644 --- a/src/ProjectFileIO.cpp +++ b/src/ProjectFileIO.cpp @@ -35,6 +35,7 @@ Paul Licameli split from AudacityProject.cpp #include "widgets/ProgressDialog.h" #include "wxFileNameWrapper.h" #include "xml/XMLFileReader.h" +#include "SentryHelper.h" // Don't change this unless the file format changes // in an irrevocable way @@ -511,6 +512,9 @@ int ProjectFileIO::Exec(const char *query, const ExecCB &callback) if (rc != SQLITE_ABORT && errmsg) { + ADD_EXCEPTION_CONTEXT("sqlite3.query", query); + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + SetDBError( XO("Failed to execute a project file command:\n\n%s").Format(query), Verbatim(errmsg), @@ -571,6 +575,10 @@ bool ProjectFileIO::GetBlob(const char *sql, wxMemoryBuffer &buffer) rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr); if (rc != SQLITE_OK) { + ADD_EXCEPTION_CONTEXT("sqlite3.query", sql); + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "ProjectGileIO::GetBlob::prepare"); + SetDBError( XO("Unable to prepare project file command:\n\n%s").Format(sql) ); @@ -587,6 +595,10 @@ bool ProjectFileIO::GetBlob(const char *sql, wxMemoryBuffer &buffer) if (rc != SQLITE_ROW) { + ADD_EXCEPTION_CONTEXT("sqlite3.query", sql); + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "ProjectGileIO::GetBlob::step"); + SetDBError( XO("Failed to retrieve data from the project file.\nThe following command failed:\n\n%s").Format(sql) ); @@ -729,6 +741,9 @@ bool ProjectFileIO::DeleteBlocks(const BlockIDs &blockids, bool complement) rc = sqlite3_create_function(db, "inset", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC, const_cast(p), InSet, nullptr, nullptr); if (rc != SQLITE_OK) { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "ProjectGileIO::DeleteBlocks::create_function"); + /* i18n-hint: An error message. Don't translate inset or blockids.*/ SetDBError(XO("Unable to add 'inset' function (can't verify blockids)")); return false; @@ -743,6 +758,10 @@ bool ProjectFileIO::DeleteBlocks(const BlockIDs &blockids, bool complement) rc = sqlite3_exec(db, sql, nullptr, nullptr, nullptr); if (rc != SQLITE_OK) { + ADD_EXCEPTION_CONTEXT("sqlite3.query", sql.ToStdString()); + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "ProjectGileIO::GetBlob"); + if( rc==SQLITE_READONLY) /* i18n-hint: An error message. Don't translate blockfiles.*/ SetDBError(XO("Project is read only\n(Unable to work with the blockfiles)")); @@ -852,6 +871,10 @@ bool ProjectFileIO::CopyTo(const FilePath &destpath, // Only capture the error if there wasn't a previous error if (result != SQLITE_OK && (rc == SQLITE_DONE || rc == SQLITE_OK)) { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT( + "sqlite3.context", "ProjectGileIO::CopyTo.cleanup"); + SetDBError( XO("Failed to rollback transaction during import") ); @@ -925,6 +948,10 @@ bool ProjectFileIO::CopyTo(const FilePath &destpath, nullptr); if (rc != SQLITE_OK) { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT( + "sqlite3.context", "ProjectGileIO::CopyTo.prepare"); + SetDBError( XO("Unable to prepare project file command:\n\n%s").Format(sql) ); @@ -955,6 +982,10 @@ bool ProjectFileIO::CopyTo(const FilePath &destpath, rc = sqlite3_bind_int64(stmt, 1, blockid); if (rc != SQLITE_OK) { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT( + "sqlite3.context", "ProjectGileIO::CopyTo.bind"); + SetDBError( XO("Failed to bind SQL parameter") ); @@ -966,6 +997,10 @@ bool ProjectFileIO::CopyTo(const FilePath &destpath, rc = sqlite3_step(stmt); if (rc != SQLITE_DONE) { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT( + "sqlite3.context", "ProjectGileIO::CopyTo.step"); + SetDBError( XO("Failed to update the project file.\nThe following command failed:\n\n%s").Format(sql) ); @@ -975,6 +1010,10 @@ bool ProjectFileIO::CopyTo(const FilePath &destpath, // Reset statement to beginning if (sqlite3_reset(stmt) != SQLITE_OK) { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT( + "sqlite3.context", "ProjectGileIO::CopyTo.reset"); + THROW_INCONSISTENCY_EXCEPTION; } @@ -1005,6 +1044,9 @@ bool ProjectFileIO::CopyTo(const FilePath &destpath, rc = sqlite3_exec(db, "DETACH DATABASE outbound;", nullptr, nullptr, nullptr); if (rc != SQLITE_OK) { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "ProjectGileIO::CopyTo::detach"); + SetDBError( XO("Destination project could not be detached") ); @@ -1729,6 +1771,9 @@ bool ProjectFileIO::AutoSaveDelete(sqlite3 *db /* = nullptr */) rc = sqlite3_exec(db, "DELETE FROM autosave;", nullptr, nullptr, nullptr); if (rc != SQLITE_OK) { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "ProjectGileIO::AutoSaveDelete"); + SetDBError( XO("Failed to remove the autosave information from the project file.") ); @@ -1769,6 +1814,10 @@ bool ProjectFileIO::WriteDoc(const char *table, rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr); if (rc != SQLITE_OK) { + ADD_EXCEPTION_CONTEXT("sqlite3.query", sql); + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "ProjectGileIO::WriteDoc::prepare"); + SetDBError( XO("Unable to prepare project file command:\n\n%s").Format(sql) ); @@ -1784,6 +1833,10 @@ bool ProjectFileIO::WriteDoc(const char *table, if (sqlite3_bind_blob(stmt, 1, dict.GetData(), dict.GetDataLen(), SQLITE_STATIC) || sqlite3_bind_blob(stmt, 2, data.GetData(), data.GetDataLen(), SQLITE_STATIC)) { + ADD_EXCEPTION_CONTEXT("sqlite3.query", sql); + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "ProjectGileIO::WriteDoc::bind"); + SetDBError( XO("Unable to bind to blob") ); @@ -1793,6 +1846,10 @@ bool ProjectFileIO::WriteDoc(const char *table, rc = sqlite3_step(stmt); if (rc != SQLITE_DONE) { + ADD_EXCEPTION_CONTEXT("sqlite3.query", sql); + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "ProjectGileIO::WriteDoc::step"); + SetDBError( XO("Failed to update the project file.\nThe following command failed:\n\n%s").Format(sql) ); @@ -2259,7 +2316,7 @@ void ProjectFileIO::ShowError(wxWindow *parent, const TranslatableString &message, const wxString &helpPage) { - ShowErrorDialog(parent, dlogTitle, message, helpPage, true, GetLastLog()); + ShowExceptionDialog(parent, dlogTitle, message, helpPage, true, GetLastLog()); } const TranslatableString &ProjectFileIO::GetLastError() const @@ -2393,6 +2450,9 @@ int64_t ProjectFileIO::GetDiskUsage(DBConnection &conn, SampleBlockID blockid /* "SELECT rootpage FROM sqlite_master WHERE tbl_name = 'sampleblocks';"); if (stmt == nullptr || sqlite3_step(stmt) != SQLITE_ROW) { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(sqlite3_errcode(conn.DB()))); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "ProjectGileIO::GetDiskUsage"); + return 0; } diff --git a/src/SqliteSampleBlock.cpp b/src/SqliteSampleBlock.cpp index f077b5b85..6819cbea7 100644 --- a/src/SqliteSampleBlock.cpp +++ b/src/SqliteSampleBlock.cpp @@ -18,6 +18,8 @@ Paul Licameli -- split from SampleBlock.cpp and SampleBlock.h #include "SampleBlock.h" // to inherit +#include "SentryHelper.h" + class SqliteSampleBlockFactory; ///\brief Implementation of @ref SampleBlock using Sqlite database @@ -557,6 +559,10 @@ size_t SqliteSampleBlock::GetBlob(void *dest, // preconditions; should return SQL_OK which is 0 if (sqlite3_bind_int64(stmt, 1, mBlockID)) { + ADD_EXCEPTION_CONTEXT( + "sqlite3.rc", std::to_string(sqlite3_errcode(Conn()->DB()))); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::GetBlob::bind"); + wxASSERT_MSG(false, wxT("Binding failed...bug!!!")); } @@ -564,6 +570,9 @@ size_t SqliteSampleBlock::GetBlob(void *dest, rc = sqlite3_step(stmt); if (rc != SQLITE_ROW) { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::GetBlob::step"); + wxLogDebug(wxT("SqliteSampleBlock::GetBlob - SQLITE error %s"), sqlite3_errmsg(db)); // Clear statement bindings and rewind statement @@ -675,6 +684,10 @@ void SqliteSampleBlock::Load(SampleBlockID sbid) // preconditions; should return SQL_OK which is 0 if (sqlite3_bind_int64(stmt, 1, sbid)) { + + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(sqlite3_errcode(Conn()->DB()))); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::Load::bind"); + wxASSERT_MSG(false, wxT("Binding failed...bug!!!")); } @@ -682,6 +695,11 @@ void SqliteSampleBlock::Load(SampleBlockID sbid) rc = sqlite3_step(stmt); if (rc != SQLITE_ROW) { + + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::Load::step"); + + wxLogDebug(wxT("SqliteSampleBlock::Load - SQLITE error %s"), sqlite3_errmsg(db)); // Clear statement bindings and rewind statement @@ -734,6 +752,12 @@ void SqliteSampleBlock::Commit(Sizes sizes) sqlite3_bind_blob(stmt, 6, mSummary64k.get(), mSummary64kBytes, SQLITE_STATIC) || sqlite3_bind_blob(stmt, 7, mSamples.get(), mSampleBytes, SQLITE_STATIC)) { + + ADD_EXCEPTION_CONTEXT( + "sqlite3.rc", std::to_string(sqlite3_errcode(Conn()->DB()))); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::Commit::bind"); + + wxASSERT_MSG(false, wxT("Binding failed...bug!!!")); } @@ -741,6 +765,9 @@ void SqliteSampleBlock::Commit(Sizes sizes) rc = sqlite3_step(stmt); if (rc != SQLITE_DONE) { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::Commit::step"); + wxLogDebug(wxT("SqliteSampleBlock::Commit - SQLITE error %s"), sqlite3_errmsg(db)); // Clear statement bindings and rewind statement @@ -783,6 +810,10 @@ void SqliteSampleBlock::Delete() // preconditions; should return SQL_OK which is 0 if (sqlite3_bind_int64(stmt, 1, mBlockID)) { + ADD_EXCEPTION_CONTEXT( + "sqlite3.rc", std::to_string(sqlite3_errcode(Conn()->DB()))); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::Delete::bind"); + wxASSERT_MSG(false, wxT("Binding failed...bug!!!")); } @@ -790,6 +821,9 @@ void SqliteSampleBlock::Delete() rc = sqlite3_step(stmt); if (rc != SQLITE_DONE) { + ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc)); + ADD_EXCEPTION_CONTEXT("sqlite3.context", "SqliteSampleBlock::Delete::step"); + wxLogDebug(wxT("SqliteSampleBlock::Load - SQLITE error %s"), sqlite3_errmsg(db)); // Clear statement bindings and rewind statement @@ -995,3 +1029,4 @@ static struct Injector ); } } injector; + \ No newline at end of file