diff --git a/src/libs/clangsupport/filepathstorage.h b/src/libs/clangsupport/filepathstorage.h index 00fa644c55f..69388a45d24 100644 --- a/src/libs/clangsupport/filepathstorage.h +++ b/src/libs/clangsupport/filepathstorage.h @@ -65,7 +65,9 @@ public: transaction.commit(); return directoryId; - } catch (Sqlite::StatementIsBusy &) { + } catch (const Sqlite::StatementIsBusy &) { + return fetchDirectoryId(directoryPath); + } catch (const Sqlite::ConstraintPreventsModification &) { return fetchDirectoryId(directoryPath); } } @@ -140,7 +142,9 @@ public: transaction.commit(); return sourceId; - } catch (Sqlite::StatementIsBusy &) { + } catch (const Sqlite::StatementIsBusy &) { + return fetchSourceId(directoryId, sourceName); + } catch (const Sqlite::ConstraintPreventsModification &) { return fetchSourceId(directoryId, sourceName); } } diff --git a/src/libs/sqlite/sqlitebasestatement.cpp b/src/libs/sqlite/sqlitebasestatement.cpp index 1db31ffabd8..e67468673a2 100644 --- a/src/libs/sqlite/sqlitebasestatement.cpp +++ b/src/libs/sqlite/sqlitebasestatement.cpp @@ -372,7 +372,7 @@ void BaseStatement::throwStatementIsMisused(const char *whatHasHappened) const void BaseStatement::throwConstraintPreventsModification(const char *whatHasHappened) const { - throw ContraintPreventsModification(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())); + throw ConstraintPreventsModification(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())); } void BaseStatement::throwNoValuesToFetch(const char *whatHasHappened) const diff --git a/src/libs/sqlite/sqliteexception.h b/src/libs/sqlite/sqliteexception.h index 3d6dfb5129e..8edfd984ef4 100644 --- a/src/libs/sqlite/sqliteexception.h +++ b/src/libs/sqlite/sqliteexception.h @@ -87,11 +87,20 @@ public: } }; -class ContraintPreventsModification : public Exception +class IoError : public Exception { public: - ContraintPreventsModification(const char *whatErrorHasHappen, - Utils::SmallString &&sqliteErrorMessage = Utils::SmallString()) + IoError(const char *whatErrorHasHappen) + : Exception(whatErrorHasHappen) + { + } +}; + +class ConstraintPreventsModification : public Exception +{ +public: + ConstraintPreventsModification(const char *whatErrorHasHappen, + Utils::SmallString &&sqliteErrorMessage = Utils::SmallString()) : Exception(whatErrorHasHappen, std::move(sqliteErrorMessage)) { } diff --git a/tests/unit/unittest/filepathstorage-test.cpp b/tests/unit/unittest/filepathstorage-test.cpp index 322c50863cb..f20ee522251 100644 --- a/tests/unit/unittest/filepathstorage-test.cpp +++ b/tests/unit/unittest/filepathstorage-test.cpp @@ -235,7 +235,7 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingSourceIdForUnknownEntry) storage.fetchSourceId(5, "unknownfile.h"); } -TEST_F(FilePathStorage, CallSelectAndWriteForFetchingDirectoryIdTwoTimesIfTheDatabaseIsBusyInBeginBecauseTheTableAlreadyChanged) +TEST_F(FilePathStorage, RestartFetchDirectoryIDIfTheDatabaseIsBusyInBeginBecauseTheTableAlreadyChanged) { InSequence s; @@ -269,7 +269,25 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingDirectoryIdTwoTimesIfTheDat storage.fetchDirectoryId("/other/unknow/path"); } -TEST_F(FilePathStorage, CallSelectAndWriteForFetchingSourceTwoTimesIfTheDatabaseIsBusyInBeginBecauseTheTableAlreadyChanged) +TEST_F(FilePathStorage, CallSelectAndWriteForFetchingDirectoryIdTwoTimesIfTheIndexIsConstraintBecauseTheEntryExistsAlready) +{ + InSequence s; + + EXPECT_CALL(mockDatabase,deferredBegin()); + EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, + valueReturnInt32(Eq("/other/unknow/path"))); + EXPECT_CALL(insertIntoDirectories, write(TypedEq("/other/unknow/path"))) + .WillOnce(Throw(Sqlite::ConstraintPreventsModification("busy"))); + EXPECT_CALL(mockDatabase, rollback()); + EXPECT_CALL(mockDatabase,deferredBegin()); + EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, + valueReturnInt32(Eq("/other/unknow/path"))); + EXPECT_CALL(mockDatabase, commit()); + + storage.fetchDirectoryId("/other/unknow/path"); +} + +TEST_F(FilePathStorage, RestartFetchSourceIdIfTheDatabaseIsBusyInBeginBecauseTheTableAlreadyChanged) { InSequence s; @@ -303,6 +321,24 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingSourceTwoTimesIfTheDatabase storage.fetchSourceId(5, "otherunknownfile.h"); } +TEST_F(FilePathStorage, CallSelectAndWriteForFetchingSourceTwoTimesIfTheIndexIsConstraintBecauseTheEntryExistsAlready) +{ + InSequence s; + + EXPECT_CALL(mockDatabase,deferredBegin()); + EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, + valueReturnInt32(5, Eq("otherunknownfile.h"))); + EXPECT_CALL(insertIntoSources, write(5, TypedEq("otherunknownfile.h"))) + .WillOnce(Throw(Sqlite::ConstraintPreventsModification("busy")));; + EXPECT_CALL(mockDatabase, rollback()); + EXPECT_CALL(mockDatabase,deferredBegin()); + EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, + valueReturnInt32(5, Eq("otherunknownfile.h"))); + EXPECT_CALL(mockDatabase, commit()); + + storage.fetchSourceId(5, "otherunknownfile.h"); +} + TEST_F(FilePathStorage, SelectAllDirectories) { auto directories = storage.fetchAllDirectories(); @@ -379,6 +415,57 @@ TEST_F(FilePathStorage, ThrowAsFetchingSourceNameForNonExistingId) ASSERT_THROW(storage.fetchSourceName(12), ClangBackEnd::SourceNameIdDoesNotExists); } +TEST_F(FilePathStorage, RestartFetchSourceNameIfTheDatabaseIsBusyInBegin) +{ + InSequence s; + + EXPECT_CALL(mockDatabase, deferredBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); + EXPECT_CALL(mockDatabase, rollback()).Times(0); + EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(selectSourceNameFromSourcesBySourceId, valueReturnSmallString(42)); + EXPECT_CALL(mockDatabase, commit()); + + storage.fetchSourceName(42); +} + +TEST_F(FilePathStorage, RestartFetchDirectoryPathIfTheDatabaseIsBusyInBegin) +{ + InSequence s; + + EXPECT_CALL(mockDatabase, deferredBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); + EXPECT_CALL(mockDatabase, rollback()).Times(0); + EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(selectDirectoryPathFromDirectoriesByDirectoryId, valueReturnPathString(5)); EXPECT_CALL(mockDatabase, commit()); + + storage.fetchDirectoryPath(5); +} + +TEST_F(FilePathStorage, RestartFetchAllDirectoriesIfBeginIsBusy) +{ + InSequence s; + + EXPECT_CALL(mockDatabase, deferredBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); + EXPECT_CALL(mockDatabase, rollback()).Times(0); + EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(selectAllDirectories, valuesReturnStdVectorDirectory(256)); + EXPECT_CALL(mockDatabase, commit()); + + storage.fetchAllDirectories(); +} + +TEST_F(FilePathStorage, RestartFetchAllSourcesIfBeginIsBusy) +{ + InSequence s; + + EXPECT_CALL(mockDatabase, deferredBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); + EXPECT_CALL(mockDatabase, rollback()).Times(0); + EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(selectAllSources, valuesReturnStdVectorSource(8192)); + EXPECT_CALL(mockDatabase, commit()); + + storage.fetchAllSources(); +} + void FilePathStorage::SetUp() { ON_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath,