From f1395ff62188cd177406f4eeb7a7fe275cd07d68 Mon Sep 17 00:00:00 2001 From: Dmitry Vedenko Date: Mon, 29 Mar 2021 17:45:12 +0300 Subject: [PATCH] Bug 2718 - improve the error message when opening a project in a read-only directory. --- src/DBConnection.cpp | 18 +++++++++++++++--- src/DBConnection.h | 7 +++++-- src/ProjectFileIO.cpp | 31 ++++++++++++++++++++++++------- src/ProjectFileIO.h | 11 +++++++---- 4 files changed, 51 insertions(+), 16 deletions(-) diff --git a/src/DBConnection.cpp b/src/DBConnection.cpp index dfacdabfd..61c5a1ef4 100644 --- a/src/DBConnection.cpp +++ b/src/DBConnection.cpp @@ -63,25 +63,37 @@ bool DBConnection::ShouldBypass() } void DBConnection::SetError( - const TranslatableString &msg, const TranslatableString &libraryError) + const TranslatableString &msg, const TranslatableString &libraryError, int errorCode) { wxLogMessage(wxT("Connection msg: %s"), msg.Debug()); + if (!libraryError.empty()) wxLogMessage(wxT("Connection error: %s"), libraryError.Debug()); mpErrors->mLastError = msg; mpErrors->mLibraryError = libraryError; + mpErrors->mErrorCode = errorCode; } void DBConnection::SetDBError( - const TranslatableString &msg, const TranslatableString &libraryError) + const TranslatableString &msg, const TranslatableString &libraryError, int errorCode) { + mpErrors->mErrorCode = errorCode < 0 ? + sqlite3_errcode(DB()) : errorCode; + mpErrors->mLastError = msg; - wxLogMessage(wxT("SQLite error: %s"), mpErrors->mLastError.Debug()); + + wxLogMessage( + wxT("SQLite error (%d): %s"), + mpErrors->mErrorCode, + mpErrors->mLastError.Debug() + ); + printf("SQLite error: %s", mpErrors->mLastError.Debug().mb_str().data()); mpErrors->mLibraryError = libraryError.empty() ? Verbatim(sqlite3_errmsg(DB())) : libraryError; + wxLogMessage(wxT(" Lib error: %s"), mpErrors->mLibraryError.Debug()); printf(" Lib error: %s", mpErrors->mLibraryError.Debug().mb_str().data()); } diff --git a/src/DBConnection.h b/src/DBConnection.h index 7a37fdf7a..7a1c39ad7 100644 --- a/src/DBConnection.h +++ b/src/DBConnection.h @@ -31,6 +31,7 @@ struct DBConnectionErrors { TranslatableString mLastError; TranslatableString mLibraryError; + int mErrorCode { 0 }; }; class DBConnection @@ -84,12 +85,14 @@ public: //! Just set stored errors void SetError( const TranslatableString &msg, - const TranslatableString &libraryError = {} ); + const TranslatableString &libraryError = {}, + int errorCode = {}); //! Set stored errors and write to log; and default libraryError to what database library reports void SetDBError( const TranslatableString &msg, - const TranslatableString &libraryError = {} ); + const TranslatableString& libraryError = {}, + int errorCode = -1); private: bool ModeConfig(sqlite3 *db, const char *schema, const char *config); diff --git a/src/ProjectFileIO.cpp b/src/ProjectFileIO.cpp index af3645d3c..961eb4a53 100644 --- a/src/ProjectFileIO.cpp +++ b/src/ProjectFileIO.cpp @@ -499,7 +499,8 @@ int ProjectFileIO::Exec(const char *query, const ExecCB &callback) { SetDBError( XO("Failed to execute a project file command:\n\n%s").Format(query), - Verbatim(errmsg) + Verbatim(errmsg), + rc ); } if (errmsg) @@ -596,6 +597,17 @@ bool ProjectFileIO::CheckVersion() wxString result; if (!GetValue("SELECT Count(*) FROM sqlite_master WHERE type='table';", result)) { + // Bug 2718 workaround for a better error message: + // If at this point we get SQLITE_CANTOPEN, then the directory is read-only + if (GetLastErrorCode() == SQLITE_CANTOPEN) + { + SetError( + /* i18n-hint: An error message. */ + XO("Project is in a read only directory\n(Unable to create the required temporary files)"), + GetLibraryError() + ); + } + return false; } @@ -2170,30 +2182,35 @@ wxLongLong ProjectFileIO::GetFreeDiskSpace() const return -1; } -const TranslatableString &ProjectFileIO::GetLastError() +const TranslatableString &ProjectFileIO::GetLastError() const { return mpErrors->mLastError; } -const TranslatableString &ProjectFileIO::GetLibraryError() +const TranslatableString &ProjectFileIO::GetLibraryError() const { return mpErrors->mLibraryError; } +int ProjectFileIO::GetLastErrorCode() const +{ + return mpErrors->mErrorCode; +} + void ProjectFileIO::SetError( - const TranslatableString &msg, const TranslatableString &libraryError ) + const TranslatableString& msg, const TranslatableString& libraryError, int errorCode) { auto &currConn = CurrConn(); if (currConn) - currConn->SetError(msg, libraryError); + currConn->SetError(msg, libraryError, errorCode); } void ProjectFileIO::SetDBError( - const TranslatableString &msg, const TranslatableString &libraryError) + const TranslatableString &msg, const TranslatableString &libraryError, int errorCode) { auto &currConn = CurrConn(); if (currConn) - currConn->SetDBError(msg, libraryError); + currConn->SetDBError(msg, libraryError, errorCode); } void ProjectFileIO::SetBypass() diff --git a/src/ProjectFileIO.h b/src/ProjectFileIO.h index d21355886..5425c8a3a 100644 --- a/src/ProjectFileIO.h +++ b/src/ProjectFileIO.h @@ -114,8 +114,9 @@ public: // specific database. This is the workhorse for the above 3 methods. static int64_t GetDiskUsage(DBConnection &conn, SampleBlockID blockid); - const TranslatableString &GetLastError(); - const TranslatableString &GetLibraryError(); + const TranslatableString &GetLastError() const; + const TranslatableString &GetLibraryError() const; + int GetLastErrorCode() const; // Provides a means to bypass "DELETE"s at shutdown if the database // is just going to be deleted anyway. This prevents a noticeable @@ -256,11 +257,13 @@ private: //! Just set stored errors void SetError(const TranslatableString & msg, - const TranslatableString &libraryError = {}); + const TranslatableString& libraryError = {}, + int errorCode = {}); //! Set stored errors and write to log; and default libraryError to what database library reports void SetDBError(const TranslatableString & msg, - const TranslatableString &libraryError = {}); + const TranslatableString& libraryError = {}, + int errorCode = -1); bool ShouldCompact(const std::vector &tracks);