diff --git a/include/SQLiteCpp/Database.h b/include/SQLiteCpp/Database.h index 65a2c96..190446b 100644 --- a/include/SQLiteCpp/Database.h +++ b/include/SQLiteCpp/Database.h @@ -55,11 +55,15 @@ public: * * @param[in] apFilename UTF-8 path/uri to the database file ("filename" sqlite3 parameter) * @param[in] aFlags SQLITE_OPEN_READONLY/SQLITE_OPEN_READWRITE/SQLITE_OPEN_CREATE... + * @param[in] aTimeoutMs Amount of milliseconds to wait before returning SQLITE_BUSY (see setBusyTimeout()) * @param[in] apVfs UTF-8 name of custom VFS to use, or nullptr for sqlite3 default * * @throw SQLite::Exception in case of error */ - Database(const char* apFilename, const int aFlags = SQLITE_OPEN_READONLY, const char* apVfs = NULL); + Database(const char* apFilename, + const int aFlags = SQLITE_OPEN_READONLY, + const int aTimeoutMs = 0, + const char* apVfs = NULL); /** * @brief Open the provided database UTF-8 filename. @@ -73,11 +77,15 @@ public: * * @param[in] aFilename UTF-8 path/uri to the database file ("filename" sqlite3 parameter) * @param[in] aFlags SQLITE_OPEN_READONLY/SQLITE_OPEN_READWRITE/SQLITE_OPEN_CREATE... + * @param[in] aTimeoutMs Amount of milliseconds to wait before returning SQLITE_BUSY (see setBusyTimeout()) * @param[in] aVfs UTF-8 name of custom VFS to use, or empty string for sqlite3 default * * @throw SQLite::Exception in case of error */ - Database(const std::string& aFilename, const int aFlags = SQLITE_OPEN_READONLY, const std::string& aVfs = ""); + Database(const std::string& aFilename, + const int aFlags = SQLITE_OPEN_READONLY, + const int aTimeoutMs = 0, + const std::string& aVfs = ""); /** * @brief Close the SQLite database connection. diff --git a/src/Database.cpp b/src/Database.cpp index 649d49e..bf94675 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -26,7 +26,10 @@ namespace SQLite // Open the provided database UTF-8 filename with SQLITE_OPEN_xxx provided flags. -Database::Database(const char* apFilename, const int aFlags /*= SQLITE_OPEN_READONLY*/, const char* apVfs /*= NULL*/) : +Database::Database(const char* apFilename, + const int aFlags /* = SQLITE_OPEN_READONLY*/, + const int aTimeoutMs /* = 0 */, + const char* apVfs /* = NULL*/) : mpSQLite(NULL), mFilename(apFilename) { @@ -37,10 +40,18 @@ Database::Database(const char* apFilename, const int aFlags /*= SQLITE_OPEN_READ sqlite3_close(mpSQLite); // close is required even in case of error on opening throw SQLite::Exception(strerr); } + + if (aTimeoutMs > 0) + { + setBusyTimeout(aTimeoutMs); + } } // Open the provided database UTF-8 filename with SQLITE_OPEN_xxx provided flags. -Database::Database(const std::string& aFilename, const int aFlags /*= SQLITE_OPEN_READONLY*/, const std::string& aVfs) : +Database::Database(const std::string& aFilename, + const int aFlags /* = SQLITE_OPEN_READONLY*/, + const int aTimeoutMs /* = 0 */, + const std::string& aVfs /* = "" */) : mpSQLite(NULL), mFilename(aFilename) { @@ -51,6 +62,11 @@ Database::Database(const std::string& aFilename, const int aFlags /*= SQLITE_OPE sqlite3_close(mpSQLite); // close is required even in case of error on opening throw SQLite::Exception(strerr); } + + if (aTimeoutMs > 0) + { + setBusyTimeout(aTimeoutMs); + } } // Close the SQLite database connection. diff --git a/tests/Database_test.cpp b/tests/Database_test.cpp index 5414ef1..57a8cd2 100644 --- a/tests/Database_test.cpp +++ b/tests/Database_test.cpp @@ -32,7 +32,8 @@ TEST(Database, ctorExecCreateDropExist) { remove("test.db3"); { // Try to open an unexisting database - EXPECT_THROW(SQLite::Database not_found("test.db3"), SQLite::Exception); + std::string filename = "test.db3"; + EXPECT_THROW(SQLite::Database not_found(filename), SQLite::Exception); // Create a new database SQLite::Database db("test.db3", SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); @@ -92,20 +93,31 @@ TEST(Database, inMemory) { } // Close an destroy DB } -#if SQLITE_VERSION_NUMBER >= 3007015 // first version with PRAGMA busy_timeout +#if SQLITE_VERSION_NUMBER >= 3007015 // SQLite v3.7.15 is first version with PRAGMA busy_timeout TEST(Database, busyTimeout) { - // Create a new database - SQLite::Database db(":memory:"); - // Busy timeout default to 0ms: any contention between threads or process leads to SQLITE_BUSY error - EXPECT_EQ(0, db.execAndGet("PRAGMA busy_timeout").getInt()); + { + // Create a new database with default timeout of 0ms + SQLite::Database db(":memory:"); + // Busy timeout default to 0ms: any contention between threads or process leads to SQLITE_BUSY error + EXPECT_EQ(0, db.execAndGet("PRAGMA busy_timeout").getInt()); - // Set a non null busy timeout: any contention between threads will leads to as much retry as possible during the time - db.setBusyTimeout(5000); - EXPECT_EQ(5000, db.execAndGet("PRAGMA busy_timeout").getInt()); + // Set a non null busy timeout: any contention between threads will leads to as much retry as possible during the time + db.setBusyTimeout(5000); + EXPECT_EQ(5000, db.execAndGet("PRAGMA busy_timeout").getInt()); - // Reset timeout to null - db.setBusyTimeout(0); - EXPECT_EQ(0, db.execAndGet("PRAGMA busy_timeout").getInt()); + // Reset timeout to 0 + db.setBusyTimeout(0); + EXPECT_EQ(0, db.execAndGet("PRAGMA busy_timeout").getInt()); + } + { + // Create a new database with a non null busy timeout + SQLite::Database db(":memory:", SQLITE_OPEN_READWRITE, 5000); + EXPECT_EQ(5000, db.execAndGet("PRAGMA busy_timeout").getInt()); + + // Reset timeout to null + db.setBusyTimeout(0); + EXPECT_EQ(0, db.execAndGet("PRAGMA busy_timeout").getInt()); + } } #endif // SQLITE_VERSION_NUMBER >= 3007015