diff options
author | Jonathan Marshall <jmarshall@never.you.mind> | 2011-02-26 23:17:52 +1300 |
---|---|---|
committer | Jonathan Marshall <jmarshall@never.you.mind> | 2011-02-26 23:18:03 +1300 |
commit | 0dcaf1fb822cb8cab3fed6a61118c20ac9b2c7e8 (patch) | |
tree | 8f5663ac6d6732ee857597c7c22228688f3e3e24 | |
parent | 3df64e8969f9d2a821dcd834cc5ddc90871fccbf (diff) | |
parent | d153d81a509e00ecbc10d636ebbbd11ae7b562e5 (diff) |
Merge backup_on_update_library branch, allowing a separate .db file per database version, meaning you can revert to an earlier version of XBMC and still have your old database intact. Does not work with mysql.
-rw-r--r-- | xbmc/TextureDatabase.h | 2 | ||||
-rw-r--r-- | xbmc/ViewDatabase.h | 2 | ||||
-rw-r--r-- | xbmc/addons/AddonDatabase.h | 2 | ||||
-rw-r--r-- | xbmc/dbwrappers/Database.cpp | 128 | ||||
-rw-r--r-- | xbmc/dbwrappers/Database.h | 8 | ||||
-rw-r--r-- | xbmc/dbwrappers/dataset.cpp | 2 | ||||
-rw-r--r-- | xbmc/dbwrappers/dataset.h | 2 | ||||
-rw-r--r-- | xbmc/dbwrappers/mysqldataset.cpp | 6 | ||||
-rw-r--r-- | xbmc/dbwrappers/mysqldataset.h | 2 | ||||
-rw-r--r-- | xbmc/dbwrappers/sqlitedataset.cpp | 13 | ||||
-rw-r--r-- | xbmc/dbwrappers/sqlitedataset.h | 2 | ||||
-rw-r--r-- | xbmc/music/MusicDatabase.h | 2 | ||||
-rw-r--r-- | xbmc/programs/ProgramDatabase.h | 2 | ||||
-rw-r--r-- | xbmc/video/VideoDatabase.h | 2 |
14 files changed, 110 insertions, 65 deletions
diff --git a/xbmc/TextureDatabase.h b/xbmc/TextureDatabase.h index 52c147ab7a..b1257df7e4 100644 --- a/xbmc/TextureDatabase.h +++ b/xbmc/TextureDatabase.h @@ -61,5 +61,5 @@ protected: virtual bool CreateTables(); virtual bool UpdateOldVersion(int version); virtual int GetMinVersion() const { return 6; }; - const char *GetDefaultDBName() const { return "Textures"; }; + const char *GetBaseDBName() const { return "Textures"; }; }; diff --git a/xbmc/ViewDatabase.h b/xbmc/ViewDatabase.h index 448dcea957..27ee539019 100644 --- a/xbmc/ViewDatabase.h +++ b/xbmc/ViewDatabase.h @@ -38,5 +38,5 @@ protected: virtual bool CreateTables(); virtual bool UpdateOldVersion(int version); virtual int GetMinVersion() const { return 3; }; - const char *GetDefaultDBName() const { return "ViewModes"; }; + const char *GetBaseDBName() const { return "ViewModes"; }; }; diff --git a/xbmc/addons/AddonDatabase.h b/xbmc/addons/AddonDatabase.h index b5c3cbaca9..744c560133 100644 --- a/xbmc/addons/AddonDatabase.h +++ b/xbmc/addons/AddonDatabase.h @@ -99,6 +99,6 @@ protected: virtual bool CreateTables(); virtual bool UpdateOldVersion(int version); virtual int GetMinVersion() const { return 12; } - const char *GetDefaultDBName() const { return "Addons"; } + const char *GetBaseDBName() const { return "Addons"; } }; diff --git a/xbmc/dbwrappers/Database.cpp b/xbmc/dbwrappers/Database.cpp index 57352a8446..11052dafc8 100644 --- a/xbmc/dbwrappers/Database.cpp +++ b/xbmc/dbwrappers/Database.cpp @@ -25,8 +25,10 @@ #include "settings/AdvancedSettings.h" #include "utils/Crc32.h" #include "filesystem/SpecialProtocol.h" +#include "filesystem/File.h" #include "utils/AutoPtrHandle.h" #include "utils/log.h" +#include "utils/URIUtils.h" using namespace AUTOPTR; using namespace dbiplus; @@ -35,8 +37,7 @@ using namespace dbiplus; CDatabase::CDatabase(void) { - m_bOpen = false; - m_iRefCount = 0; + m_openCount = 0; m_sqlite = true; m_bMultiWrite = false; } @@ -253,32 +254,81 @@ bool CDatabase::Open(DatabaseSettings &dbSettings) { if (IsOpen()) { - m_iRefCount++; + m_openCount++; return true; } m_sqlite = true; - + if ( dbSettings.type.Equals("mysql") ) { // check we have all information before we cancel the fallback - if ( ! (dbSettings.host.IsEmpty() || dbSettings.user.IsEmpty() || dbSettings.pass.IsEmpty()) ) + if ( ! (dbSettings.host.IsEmpty() || dbSettings.name.IsEmpty() || + dbSettings.user.IsEmpty() || dbSettings.pass.IsEmpty()) ) m_sqlite = false; else - CLog::Log(LOGINFO, "essential mysql database information is missing (eg. host, user, pass)"); + CLog::Log(LOGINFO, "essential mysql database information is missing (eg. host, name, user, pass)"); } - // set default database name if appropriate - if ( dbSettings.name.IsEmpty() ) - dbSettings.name = GetDefaultDBName(); - - // always safely fallback to sqlite3 + // always safely fallback to sqlite3, and use separate, versioned database if (m_sqlite) { dbSettings.type = "sqlite3"; dbSettings.host = _P(g_settings.GetDatabaseFolder()); + + int version = GetMinVersion(); + CStdString latestDb; + latestDb.Format("%s%d.db", GetBaseDBName(), version); + while (version >= 0) + { + if (version) + dbSettings.name.Format("%s%d.db", GetBaseDBName(), version); + else + dbSettings.name.Format("%s.db", GetBaseDBName()); + if (Connect(dbSettings, false)) + { + // Database exists, take a copy for our current version (if needed) and reopen that one + if (version < GetMinVersion()) + { + CLog::Log(LOGNOTICE, "Old database found - updating from version %i to %i", version, GetMinVersion()); + Close(); + CStdString currentDb = URIUtils::AddFileToFolder(dbSettings.host, dbSettings.name); + CStdString newPath = URIUtils::AddFileToFolder(dbSettings.host, latestDb); + if (!XFILE::CFile::Cache(currentDb, newPath)) + { + CLog::Log(LOGERROR, "Unable to copy old database %s to new version %s", dbSettings.name.c_str(), latestDb.c_str()); + return false; + } + dbSettings.name = latestDb; + if (!Connect(dbSettings, false)) + { + CLog::Log(LOGERROR, "Unable to open freshly copied database %s", dbSettings.name.c_str()); + return false; + } + } + // yay - we have a copy of our db, now do our worst with it + if (UpdateVersion(dbSettings.name)) + return true; + // update failed - loop around and see if we have another one available + Close(); + } + // drop back to the previous version and try that + version--; + } + // unable to open any version fall through to create a new one + dbSettings.name = latestDb; } + if (Connect(dbSettings, true) && UpdateVersion(dbSettings.name)) + return true; + // failed to update or open the database + Close(); + CLog::Log(LOGERROR, "Unable to open database %s", dbSettings.name.c_str()); + return false; +} + +bool CDatabase::Connect(DatabaseSettings &dbSettings, bool create) +{ // create the appropriate database structure if (dbSettings.type.Equals("sqlite3")) { @@ -313,14 +363,11 @@ bool CDatabase::Open(DatabaseSettings &dbSettings) m_pDS.reset(m_pDB->CreateDataset()); m_pDS2.reset(m_pDB->CreateDataset()); - if (m_pDB->connect() != DB_CONNECTION_OK) - { - CLog::Log(LOGERROR, "Unable to open database at host: %s db: %s (old version?)", dbSettings.host.c_str(), dbSettings.name.c_str()); + if (m_pDB->connect(create) != DB_CONNECTION_OK) return false; - } // test if db already exists, if not we need to create the tables - if (!m_pDB->exists()) + if (!m_pDB->exists() && create) { if (dbSettings.type.Equals("sqlite3")) { @@ -337,10 +384,20 @@ bool CDatabase::Open(DatabaseSettings &dbSettings) CreateTables(); } - // Mark our db as open here to make our destructor to properly close the file handle - m_bOpen = true; + // sqlite3 post connection operations + if (dbSettings.type.Equals("sqlite3")) + { + m_pDS->exec("PRAGMA cache_size=4096\n"); + m_pDS->exec("PRAGMA synchronous='NORMAL'\n"); + m_pDS->exec("PRAGMA count_changes='OFF'\n"); + } + + m_openCount = 1; // our database is open + return true; +} - // Database exists, check the version number +bool CDatabase::UpdateVersion(const CStdString &dbName) +{ int version = 0; m_pDS->query("SELECT idVersion FROM version\n"); if (m_pDS->num_rows() > 0) @@ -348,53 +405,40 @@ bool CDatabase::Open(DatabaseSettings &dbSettings) if (version < GetMinVersion()) { - CLog::Log(LOGNOTICE, "Attempting to update the database %s from version %i to %i", dbSettings.name.c_str(), version, GetMinVersion()); + CLog::Log(LOGNOTICE, "Attempting to update the database %s from version %i to %i", dbName.c_str(), version, GetMinVersion()); if (UpdateOldVersion(version) && UpdateVersionNumber()) CLog::Log(LOGINFO, "Update to version %i successfull", GetMinVersion()); else { - CLog::Log(LOGERROR, "Can't update the database %s from version %i to %i", dbSettings.name.c_str(), version, GetMinVersion()); - Close(); + CLog::Log(LOGERROR, "Can't update the database %s from version %i to %i", dbName.c_str(), version, GetMinVersion()); return false; } } else if (version > GetMinVersion()) { - CLog::Log(LOGERROR, "Can't open the database %s as it is a NEWER version than what we were expecting!", dbSettings.name.c_str()); - Close(); + CLog::Log(LOGERROR, "Can't open the database %s as it is a NEWER version than what we were expecting?", dbName.c_str()); return false; } - - // sqlite3 post connection operations - if (dbSettings.type.Equals("sqlite3")) - { - m_pDS->exec("PRAGMA cache_size=4096\n"); - m_pDS->exec("PRAGMA synchronous='NORMAL'\n"); - m_pDS->exec("PRAGMA count_changes='OFF'\n"); - } - - m_iRefCount++; return true; } bool CDatabase::IsOpen() { - return m_bOpen; + return m_openCount > 0; } void CDatabase::Close() { - if (!m_bOpen) - return ; + if (m_openCount == 0) + return; - if (m_iRefCount > 1) + if (m_openCount > 1) { - m_iRefCount--; - return ; + m_openCount--; + return; } - m_iRefCount--; - m_bOpen = false; + m_openCount = 0; if (NULL == m_pDB.get() ) return ; if (NULL != m_pDS.get()) m_pDS->close(); diff --git a/xbmc/dbwrappers/Database.h b/xbmc/dbwrappers/Database.h index e9cf9ff60d..24d6fa0b57 100644 --- a/xbmc/dbwrappers/Database.h +++ b/xbmc/dbwrappers/Database.h @@ -112,9 +112,10 @@ protected: virtual bool UpdateOldVersion(int version) { return true; }; virtual int GetMinVersion() const=0; - virtual const char *GetDefaultDBName() const=0; + virtual const char *GetBaseDBName() const=0; + + bool UpdateVersion(const CStdString &dbName); - bool m_bOpen; bool m_sqlite; ///< \brief whether we use sqlite (defaults to true) std::auto_ptr<dbiplus::Database> m_pDB; @@ -122,8 +123,9 @@ protected: std::auto_ptr<dbiplus::Dataset> m_pDS2; private: + bool Connect(DatabaseSettings &db, bool create); bool UpdateVersionNumber(); bool m_bMultiWrite; /*!< True if there are any queries in the queue, false otherwise */ - int m_iRefCount; + unsigned int m_openCount; }; diff --git a/xbmc/dbwrappers/dataset.cpp b/xbmc/dbwrappers/dataset.cpp index 8fce09172c..e9b8944183 100644 --- a/xbmc/dbwrappers/dataset.cpp +++ b/xbmc/dbwrappers/dataset.cpp @@ -60,7 +60,7 @@ int Database::connectFull(const char *newHost, const char *newPort, const char * db = newDb; login = newLogin; passwd = newPasswd; - return connect(); + return connect(true); } diff --git a/xbmc/dbwrappers/dataset.h b/xbmc/dbwrappers/dataset.h index 3347eb5706..190e076d26 100644 --- a/xbmc/dbwrappers/dataset.h +++ b/xbmc/dbwrappers/dataset.h @@ -115,7 +115,7 @@ public: virtual int setErr(int err_code, const char *qry)=0; virtual const char *getErrorMsg(void) { return error.c_str(); } - virtual int connect(void) { return DB_COMMAND_OK; } + virtual int connect(bool create) { return DB_COMMAND_OK; } virtual int connectFull( const char *newDb, const char *newHost=NULL, const char *newLogin=NULL, const char *newPasswd=NULL,const char *newPort=NULL); virtual void disconnect(void) { active = false; } diff --git a/xbmc/dbwrappers/mysqldataset.cpp b/xbmc/dbwrappers/mysqldataset.cpp index f1d9438073..e7399f789a 100644 --- a/xbmc/dbwrappers/mysqldataset.cpp +++ b/xbmc/dbwrappers/mysqldataset.cpp @@ -104,7 +104,7 @@ const char *MysqlDatabase::getErrorMsg() { return error.c_str(); } -int MysqlDatabase::connect() { +int MysqlDatabase::connect(bool create_new) { try { // don't reconnect if ping is ok @@ -221,7 +221,7 @@ int MysqlDatabase::query_with_reconnect(const char* query) { { CLog::Log(LOGINFO,"MYSQL server has gone. Will try %d more attempt(s) to reconnect.", attempts); active = false; - connect(); + connect(true); } // grab the latest error if not ok @@ -299,7 +299,7 @@ void MysqlDatabase::rollback_transaction() { bool MysqlDatabase::exists() { // Uncorrect name, check if tables are present inside the db - connect(); + connect(true); if (active && conn != NULL) { MYSQL_RES* res = mysql_list_dbs(conn, db.c_str()); diff --git a/xbmc/dbwrappers/mysqldataset.h b/xbmc/dbwrappers/mysqldataset.h index 04c40ce471..c005c13a64 100644 --- a/xbmc/dbwrappers/mysqldataset.h +++ b/xbmc/dbwrappers/mysqldataset.h @@ -57,7 +57,7 @@ public: virtual const char *getErrorMsg(); /* func. connects to database-server */ - virtual int connect(); + virtual int connect(bool create); /* func. disconnects from database-server */ virtual void disconnect(); /* func. creates new database */ diff --git a/xbmc/dbwrappers/sqlitedataset.cpp b/xbmc/dbwrappers/sqlitedataset.cpp index 1032a010e4..25481bc348 100644 --- a/xbmc/dbwrappers/sqlitedataset.cpp +++ b/xbmc/dbwrappers/sqlitedataset.cpp @@ -30,7 +30,6 @@ #include <string> #include "sqlitedataset.h" -#include "utils/log.h" #include "system.h" // for Sleep(), OutputDebugString() and GetLastError() using namespace std; @@ -166,7 +165,7 @@ const char *SqliteDatabase::getErrorMsg() { return error.c_str(); } -int SqliteDatabase::connect() { +int SqliteDatabase::connect(bool create) { if (host.empty() || db.empty()) return DB_CONNECTION_NONE; @@ -205,7 +204,10 @@ int SqliteDatabase::connect() { { disconnect(); - if (sqlite3_open(db_fullpath.c_str(), &conn)==SQLITE_OK) + int flags = SQLITE_OPEN_READWRITE; + if (create) + flags |= SQLITE_OPEN_CREATE; + if (sqlite3_open_v2(db_fullpath.c_str(), &conn, flags, NULL)==SQLITE_OK) { sqlite3_busy_handler(conn, busy_callback, NULL); char* err=NULL; @@ -217,13 +219,10 @@ int SqliteDatabase::connect() { return DB_CONNECTION_OK; } - CLog::Log(LOGERROR, "Unable to open database: %s (%u)", db_fullpath.c_str(), GetLastError()); return DB_CONNECTION_NONE; } catch(...) { - CLog::Log(LOGERROR, "Unable to open database: %s (%u)", - db_fullpath.c_str(), GetLastError()); } return DB_CONNECTION_NONE; } @@ -253,7 +252,7 @@ void SqliteDatabase::disconnect(void) { } int SqliteDatabase::create() { - return connect(); + return connect(true); } int SqliteDatabase::drop() { diff --git a/xbmc/dbwrappers/sqlitedataset.h b/xbmc/dbwrappers/sqlitedataset.h index 0d490ee40a..fa696eb797 100644 --- a/xbmc/dbwrappers/sqlitedataset.h +++ b/xbmc/dbwrappers/sqlitedataset.h @@ -67,7 +67,7 @@ public: virtual const char *getErrorMsg(); /* func. connects to database-server */ - virtual int connect(); + virtual int connect(bool create); /* func. disconnects from database-server */ virtual void disconnect(); /* func. creates new database */ diff --git a/xbmc/music/MusicDatabase.h b/xbmc/music/MusicDatabase.h index 6a4a3bf9dd..1cbf96fedf 100644 --- a/xbmc/music/MusicDatabase.h +++ b/xbmc/music/MusicDatabase.h @@ -215,7 +215,7 @@ protected: virtual bool CreateTables(); virtual int GetMinVersion() const { return 16; }; - const char *GetDefaultDBName() const { return "MyMusic7"; }; + const char *GetBaseDBName() const { return "MyMusic"; }; int AddAlbum(const CStdString& strAlbum1, int idArtist, const CStdString &extraArtists, const CStdString &strArtist1, int idThumb, int idGenre, const CStdString &extraGenres, int year); int AddGenre(const CStdString& strGenre); diff --git a/xbmc/programs/ProgramDatabase.h b/xbmc/programs/ProgramDatabase.h index b119956278..4f63216241 100644 --- a/xbmc/programs/ProgramDatabase.h +++ b/xbmc/programs/ProgramDatabase.h @@ -66,7 +66,7 @@ protected: virtual bool CreateTables(); virtual bool UpdateOldVersion(int version); virtual int GetMinVersion() const { return 3; }; - const char *GetDefaultDBName() const { return "MyPrograms6"; }; + const char *GetBaseDBName() const { return "MyPrograms"; }; FILETIME TimeStampToLocalTime( uint64_t timeStamp ); }; diff --git a/xbmc/video/VideoDatabase.h b/xbmc/video/VideoDatabase.h index 602bd7bc16..73bf1dd1c3 100644 --- a/xbmc/video/VideoDatabase.h +++ b/xbmc/video/VideoDatabase.h @@ -639,7 +639,7 @@ private: int RunQuery(const CStdString &sql); virtual int GetMinVersion() const { return 44; }; - const char *GetDefaultDBName() const { return "MyVideos34.db"; }; + const char *GetBaseDBName() const { return "MyVideos"; }; void ConstructPath(CStdString& strDest, const CStdString& strPath, const CStdString& strFileName); void SplitPath(const CStdString& strFileNameAndPath, CStdString& strPath, CStdString& strFileName); |