From 9ea0cffc1519866645582c366430bbe5b53e20a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Rombauts?= Date: Fri, 3 Jan 2020 22:58:36 +0100 Subject: [PATCH] Replace Database::backup() "C" implementation by calling the Backup class --- CHANGELOG.md | 3 ++- include/SQLiteCpp/Backup.h | 12 ++------- include/SQLiteCpp/Database.h | 4 +-- src/Database.cpp | 52 +++++++++--------------------------- tests/Database_test.cpp | 6 ++--- 5 files changed, 21 insertions(+), 56 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb3ff06..a45b6d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -161,4 +161,5 @@ Version 3.0.0 - January 1 2020 - CMake 3.1 minimum - Visual Studio 2015 minimum - Googletest 1.10 -- Remove Statement::isOk() deprecated in 2.2.0 when renamed to Statement::hasRow() +- Remove Statement::isOk() deprecated in 2.2.0 when renamed to Statement::hasRow() +- Replace Database::backup() "C" implementation by calling the Backup class diff --git a/include/SQLiteCpp/Backup.h b/include/SQLiteCpp/Backup.h index 70ae62f..1d36e22 100644 --- a/include/SQLiteCpp/Backup.h +++ b/include/SQLiteCpp/Backup.h @@ -27,16 +27,8 @@ namespace SQLite * A Backup object is used to backup a source database file to a destination database file * in a safe and online way. * - * Resource Acquisition Is Initialization (RAII) means that the Backup Resource - * is allocated in the constructor and released in the destructor, so that there is - * no need to worry about memory management or the validity of the underlying SQLite Backup. - * - * Thread-safety: a Backup object shall not be shared by multiple threads, because : - * 1) in the SQLite "Thread Safe" mode, "SQLite can be safely used by multiple threads - * provided that no single database connection is used simultaneously in two or more threads." - * 2) the SQLite "Serialized" mode is not supported by SQLiteC++, - * because of the way it shares the underling SQLite precompiled statement - * in a custom shared pointer (See the inner class "Statement::Ptr"). + * See also the a reference implementation of live backup taken from the official site: + * https://www.sqlite.org/backup.html */ class Backup { diff --git a/include/SQLiteCpp/Database.h b/include/SQLiteCpp/Database.h index a1ef348..1276109 100644 --- a/include/SQLiteCpp/Database.h +++ b/include/SQLiteCpp/Database.h @@ -489,9 +489,9 @@ public: * into the "main" database of open database connection, or to save the current * contents of the database into a database file on disk. * - * @return SQLITE_OK on success or an error code from SQLite. + * @throw SQLite::Exception in case of error */ - int backup(const char* zFilename, BackupType type); + void backup(const char* apFilename, BackupType aType); /** * @brief Check if aRet equal SQLITE_OK, else throw a SQLite::Exception with the SQLite error message diff --git a/src/Database.cpp b/src/Database.cpp index 521ff90..5f6f5b4 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -405,49 +406,20 @@ Header Database::getHeaderInfo(const std::string& aFilename) return h; } +void Database::backup(const char* apFilename, BackupType aType) +{ + // Open the database file identified by apFilename + Database otherDatabase(apFilename, SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE); -// This is a reference implementation of live backup taken from the official sit: -// https://www.sqlite.org/backup.html + // For a 'Save' operation, data is copied from the current Database to the other. A 'Load' is the reverse. + Database& src = (aType == Save ? *this : otherDatabase); + Database& dest = (aType == Save ? otherDatabase : *this); -int Database::backup(const char* zFilename, BackupType type) { - /* Open the database file identified by zFilename. Exit early if this fails. */ - sqlite3* pFile; - int rc = sqlite3_open(zFilename, &pFile); - if (rc == SQLITE_OK) - { - /* If this is a 'load' operation (isSave==0), then data is copied - ** from the database file just opened to database mpSQLite. - ** Otherwise, if this is a 'save' operation (isSave==1), then data - ** is copied from mpSQLite to pFile. Set the variables pFrom and - ** pTo accordingly. */ - sqlite3* pFrom = (type == Save ? getHandle() : pFile); - sqlite3* pTo = (type == Save ? pFile : getHandle()); + // Set up the backup procedure to copy between the "main" databases of each connection + Backup bkp(dest, src); + bkp.executeStep(); // Execute all steps at once - /* Set up the backup procedure to copy from the "main" database of - ** connection pFile to the main database of connection mpSQLite. - ** If something goes wrong, pBackup will be set to NULL and an error - ** code and message left in connection pTo. - ** - ** If the backup object is successfully created, call backup_step() - ** to copy data from pFile to mpSQLite. Then call backup_finish() - ** to release resources associated with the pBackup object. If an - ** error occurred, then an error code and message will be left in - ** connection pTo. If no error occurred, then the error code belonging - ** to pTo is set to SQLITE_OK. - */ - sqlite3_backup *pBackup = sqlite3_backup_init(pTo, "main", pFrom, "main"); - if (pBackup) - { - sqlite3_backup_step(pBackup, -1); - sqlite3_backup_finish(pBackup); - } - rc = sqlite3_errcode(pTo); - } - - /* Close the database connection opened on database file zFilename - ** and return the result of this function. */ - sqlite3_close(pFile); - return rc; + // RAII Finish Backup an Close the other Database } } // namespace SQLite diff --git a/tests/Database_test.cpp b/tests/Database_test.cpp index 7153954..102fac6 100644 --- a/tests/Database_test.cpp +++ b/tests/Database_test.cpp @@ -131,7 +131,7 @@ TEST(Database, inMemory) } // Close an destroy DB } -TEST(Database, import_export) +TEST(Database, backup) { // Create a new in-memory database SQLite::Database db(":memory:", SQLite::OPEN_READWRITE); @@ -141,14 +141,14 @@ TEST(Database, import_export) // Export the data into a file remove("backup"); - EXPECT_EQ(db.backup("backup", SQLite::Database::Save), SQLITE_OK); + EXPECT_NO_THROW(db.backup("backup", SQLite::Database::Save)); // Trash the table db.exec("DROP TABLE test;"); EXPECT_FALSE(db.tableExists("test")); // Import the data back from the file - EXPECT_EQ(db.backup("backup", SQLite::Database::Load), SQLITE_OK); + EXPECT_NO_THROW(db.backup("backup", SQLite::Database::Load)); EXPECT_TRUE(db.tableExists("test")); }