int main(int argc, char* argv[]) { DWORD dwError = 0; if (argc != 3) { fprintf(stderr, "usage: %s srcpath dstpath\n", argv[0]); exit(1); } dwError = BackupDB(argv[1], argv[2]); exit(dwError); }
bool dbUpgrade::UpgradeDB(wxSQLite3Database * db, const wxString& DbFileName) { int ver = GetCurrentVersion(db); if (ver == -1 || ver > dbLatestVersion) { wxMessageBox(_("MMEX database error!") + "\n\n" + wxString::Format(_("MMEX database version %i doesn't work with this MMEX version.\nPlease upgrade MMEX to newer version."), ver) , _("MMEX database upgrade"), wxOK | wxICON_ERROR); return false; } for (; ver < dbLatestVersion; ver++) { BackupDB(DbFileName, dbUpgrade::BACKUPTYPE::VERSION_UPGRADE, 999, ver); if (!UpgradeToVersion(db, ver + 1)) return false; } wxMessageBox(wxString::Format(_("MMEX database succesfully upgraded to version %i"), ver) + "\n\n" + _("We suggest a database optimization under Tools -> Database -> Optimize"), _("MMEX database upgrade"), wxOK | wxICON_INFORMATION); return true; }
//打开数据库文件 bool CDatabase::OpenDB(std::string sFileName) { //先关闭连接 CloseDB(); _pDB = new CppSQLite3DB(); try { _pDB->open(sFileName.c_str()); } catch(CppSQLite3Exception e) { return false; } catch(...) { return false; } //检测是否成功打开 if(!IsOpen()) return false; try { //词典是否存在 if(!IsExistTable(DicTableName)) {//不存在词典,则新建词典 static const char sSql[] = "CREATE TABLE %Q (key text primary key,value text,comment text)"; if(SQLERROR == this->ExecSql(sSql,DicTableName)) goto _OnError; } if(!OnCreateTables()) goto _OnError; //取得数据库文件版本 const int OldDBVersion = GetDBVersion(); if(OldDBVersion > DBVersion) { goto _OnError; } if(OldDBVersion < DBVersion) { if(!BackupDB(sFileName)) goto _OnError; if(!OnUpdateTables(OldDBVersion,DBVersion)) goto _OnError; DeleteDict(DBVersionKey); if(!InsertDict(DBVersionKey,DBVersion)) goto _OnError; } else { int nLastBackupTime = 0; if(GetDictValue(LastBackupKey,nLastBackupTime)) { int nOffTime = (int)time(NULL) - nLastBackupTime; if(nOffTime > BackupDBRate) BackupDB(sFileName); } } }catch(CppSQLite3Exception e) { assert(false); goto _OnError; } catch(...) { assert(false); goto _OnError; } return true; _OnError: { this->CloseDB(); return false; } }
/** * Tell the user that a schema needs to be upgraded, ask if that's OK, * remind them about backups, et c. The GUI buttons default to Exit. * The shell command prompting requires an explicit "yes". * * \param name What schema are we planning to upgrade? (TV? Music?) * \param upgradeAllowed In not true, and DBSchemaAutoUpgrade isn't set for * expert mode, this is just a few information messages * \param upgradeIfNoUI Default for non-interactive shells * * \todo Clarify whether the minDBMS stuff is just for upgrading, * or if it is a runtime requirement too. If the latter, * then this possibly should be called even if the schema match, * to ensure the user is informed of the MySQL upgrade requirement. * * \todo This uses GetMythUI()->IsScreenSetup() to work out if this program's * context is a GUI, but GetMythUI() might create a MythUIHelper. * Having a static bool MythUIHelper::ValidMythUI() would be much tidier? */ enum MythSchemaUpgrade SchemaUpgradeWizard::PromptForUpgrade(const char *name, const bool upgradeAllowed, const bool upgradeIfNoUI, const int minDBMSmajor, const int minDBMSminor, const int minDBMSpoint) { bool connections; // Are (other) FE/BEs connected? bool gui; // Was gContext Init'ed gui=true? bool upgradable; // Can/should we upgrade? bool validDBMS; // Do we measure up to minDBMS* ? QString warnOldDBMS; QString warnOtherCl; if (versionsBehind == -1) Compare(); #if minDBMS_is_only_for_schema_upgrades if (versionsBehind == 0) // Why was this method even called? return MYTH_SCHEMA_USE_EXISTING; #endif // Only back up the database if we haven't already successfully made a // backup and the database is old/about to be upgraded (not if it's too // new) or if a user is doing something they probably shouldn't ("expert // mode") if (((backupStatus == kDB_Backup_Unknown) || (backupStatus == kDB_Backup_Failed)) && ((upgradeAllowed && (versionsBehind > 0)) || m_expertMode)) BackupDB(); connections = CountClients() > 1; gui = GetMythUI()->IsScreenSetup() && GetMythMainWindow(); validDBMS = (minDBMSmajor == 0) // If the caller provided no version, ? true // the upgrade code can't be fussy! : CompareDBMSVersion(minDBMSmajor, minDBMSminor, minDBMSpoint) >= 0; upgradable = validDBMS && (versionsBehind > 0) && (upgradeAllowed || m_expertMode); // Build up strings used both in GUI and command shell contexts: if (connections) warnOtherCl = tr("There are also other clients using this" " database. They should be shut down first."); if (!validDBMS) warnOldDBMS = tr("Error: This version of Myth%1" " requires MySQL %2.%3.%4 or later." " You seem to be running MySQL version %5.") .arg(name).arg(minDBMSmajor).arg(minDBMSminor) .arg(minDBMSpoint).arg(GetDBMSVersion()); // // 1. Deal with the trivial cases (No user prompting required) // if (validDBMS) { // Empty database? Always upgrade, to create tables if (emptyDB) return MYTH_SCHEMA_UPGRADE; if (m_autoUpgrade && !connections && upgradable) return MYTH_SCHEMA_UPGRADE; } if (!gui && (!isatty(fileno(stdin)) || !isatty(fileno(stdout)))) { LOG(VB_GENERAL, LOG_INFO, "Console is non-interactive, can't prompt user..."); if (m_expertMode) { LOG(VB_GENERAL, LOG_CRIT, "Using existing schema."); return MYTH_SCHEMA_USE_EXISTING; } if (!validDBMS) { LOG(VB_GENERAL, LOG_CRIT, warnOldDBMS); return MYTH_SCHEMA_EXIT; } if (versionsBehind < 0) { LOG(VB_GENERAL, LOG_CRIT, QString("Error: MythTV database has newer %1 schema (%2) " "than expected (%3).") .arg(name).arg(DBver).arg(m_newSchemaVer)); return MYTH_SCHEMA_ERROR; } if (upgradeIfNoUI && validDBMS) { LOG(VB_GENERAL, LOG_CRIT, "Upgrading."); return MYTH_SCHEMA_UPGRADE; } return MYTH_SCHEMA_EXIT; } // // 2. Build up a compound message to show the user, wait for a response // enum MythSchemaUpgrade returnValue = MYTH_SCHEMA_UPGRADE; QString message; if (upgradable) { if (m_autoUpgrade && connections) { message = tr("Error: MythTV cannot upgrade the schema of this" " datatase because other clients are using it.\n\n" "Please shut them down before upgrading."); returnValue = MYTH_SCHEMA_ERROR; } else { message = tr("Warning: MythTV wants to upgrade your database,") + "\n" + tr("for the %1 schema, from %2 to %3."); if (m_expertMode) // Not translated. This string can't appear in released builds. message += "\n\nYou can try using the old schema," " but that may cause problems."; } } else if (!validDBMS) { message = warnOldDBMS; returnValue = MYTH_SCHEMA_ERROR; } else if (versionsBehind > 0) { message = tr("This version of MythTV requires an updated database. ") + tr("(schema is %1 versions behind)").arg(versionsBehind) + "\n\n" + tr("Please run mythtv-setup or mythbackend " "to update your database."); returnValue = MYTH_SCHEMA_ERROR; } else // This client is too old { if (m_expertMode) // Not translated. This string can't appear in released builds. message = "Warning: MythTV database has newer" " %1 schema (%2) than expected (%3)."; else { message = tr("Error: MythTV database has newer" " %1 schema (%2) than expected (%3)."); returnValue = MYTH_SCHEMA_ERROR; } } if (backupStatus == kDB_Backup_Failed) message += "\n" + tr("MythTV was unable to backup your database."); if (message.contains("%1")) message = message.arg(name).arg(DBver).arg(m_newSchemaVer); DatabaseParams dbParam = MythDB::getMythDB()->GetDatabaseParams(); message += "\n\n" + tr("Database Host: %1\nDatabase Name: %2") .arg(dbParam.dbHostName).arg(dbParam.dbName); if (gui) { if (returnValue == MYTH_SCHEMA_ERROR) { // Display error, return warning to caller ShowOkPopup(message); return MYTH_SCHEMA_ERROR; } returnValue = GuiPrompt(message, upgradable, m_expertMode); if (returnValue == MYTH_SCHEMA_EXIT) return MYTH_SCHEMA_EXIT; if (m_expertMode) return returnValue; // The annoying extra confirmation: if (backupStatus == kDB_Backup_Completed) { int dirPos = m_backupResult.lastIndexOf('/'); QString dirName; QString fileName; if (dirPos > 0) { fileName = m_backupResult.mid(dirPos + 1); dirName = m_backupResult.left(dirPos); } message = tr("If your system becomes unstable, a database" " backup file called\n%1\nis located in %2") .arg(fileName).arg(dirName); } else message = tr("This cannot be un-done, so having a" " database backup would be a good idea."); if (connections) message += "\n\n" + warnOtherCl; return GuiPrompt(message, upgradable, m_expertMode); } // We are not in a GUI environment, so try to prompt the user in the shell QString resp; cout << endl << message.toLocal8Bit().constData() << endl << endl; if (returnValue == MYTH_SCHEMA_ERROR) return MYTH_SCHEMA_ERROR; if (backupStatus == kDB_Backup_Failed) cout << "WARNING: MythTV was unable to backup your database." << endl << endl; else if ((backupStatus == kDB_Backup_Completed) && (m_backupResult != "")) cout << "If your system becomes unstable, " "a database backup is located in " << m_backupResult.toLocal8Bit().constData() << endl << endl; if (m_expertMode) { resp = getResponse("Would you like to use the existing schema?", "yes"); if (resp.isEmpty() || resp.left(1).toLower() == "y") return MYTH_SCHEMA_USE_EXISTING; } resp = getResponse("\nShall I upgrade this database?", "yes"); if (!resp.isEmpty() && resp.left(1).toLower() != "y") return MYTH_SCHEMA_EXIT; if (connections) cout << endl << warnOtherCl.toLocal8Bit().constData() << endl; if ((backupStatus != kDB_Backup_Completed) && (backupStatus != kDB_Backup_Empty_DB)) { resp = getResponse("\nA database backup might be a good idea" "\nAre you sure you want to upgrade?", "no"); if (resp.isEmpty() || resp.left(1).toLower() == "n") return MYTH_SCHEMA_EXIT; } return MYTH_SCHEMA_UPGRADE; }
BOOL ValidDB(CString csPath, BOOL bUpgrade) { CDittoPopupWindow *popUpMsg = NULL; try { BOOL didBackup = FALSE; CString backupFilePrefix = _T("Before_Update_To"); CppSQLite3DB db; db.open(csPath); db.execQuery(_T("SELECT lID, lDate, mText, lShortCut, lDontAutoDelete, ") _T("CRC, bIsGroup, lParentID, QuickPasteText ") _T("FROM Main")); db.execQuery(_T("SELECT lID, lParentID, strClipBoardFormat, ooData FROM Data")); db.execQuery(_T("SELECT lID, TypeText FROM Types")); try { db.execDML(_T("DROP TRIGGER delete_data_trigger")); } catch(CppSQLite3Exception& e) { e.errorCode(); } try { db.execDML(_T("DROP TRIGGER delete_copy_buffer_trigger")); } catch(CppSQLite3Exception& e) { e.errorCode(); } //This was added later so try to add each time and catch the exception here try { db.execDML(_T("CREATE TRIGGER delete_data_trigger BEFORE DELETE ON Main FOR EACH ROW\n") _T("BEGIN\n") _T("INSERT INTO MainDeletes VALUES(old.lID, datetime('now'));\n") _T("END\n")); } catch(CppSQLite3Exception& e) { if(didBackup == FALSE) didBackup = BackupDB(csPath, backupFilePrefix, &popUpMsg); e.errorCode(); } //This was added later so try to add each time and catch the exception here try { db.execQuery(_T("SELECT lID, lClipID, lCopyBuffer FROM CopyBuffers")); } catch(CppSQLite3Exception& e) { if(didBackup == FALSE) didBackup = BackupDB(csPath, backupFilePrefix, &popUpMsg); e.errorCode(); db.execDML(_T("CREATE TABLE CopyBuffers(") _T("lID INTEGER PRIMARY KEY AUTOINCREMENT, ") _T("lClipID INTEGER,") _T("lCopyBuffer INTEGER)")); } //This was added later so try to add each time and catch the exception here try { db.execQuery(_T("SELECT clipId FROM MainDeletes")); } catch(CppSQLite3Exception& e) { if(didBackup == FALSE) didBackup = BackupDB(csPath, backupFilePrefix, &popUpMsg); e.errorCode(); db.execDML(_T("CREATE TABLE MainDeletes(") _T("clipID INTEGER,") _T("modifiedDate)")); db.execDML(_T("CREATE TRIGGER MainDeletes_delete_data_trigger BEFORE DELETE ON MainDeletes FOR EACH ROW\n") _T("BEGIN\n") _T("DELETE FROM CopyBuffers WHERE lClipID = old.clipID;\n") _T("DELETE FROM Data WHERE lParentID = old.clipID;\n") _T("END\n")); } try { db.execDML(_T("CREATE INDEX Main_ParentId on Main(lParentID DESC)")); db.execDML(_T("CREATE INDEX Main_IsGroup on Main(bIsGroup DESC)")); db.execDML(_T("CREATE INDEX Main_ShortCut on Main(lShortCut DESC)")); } catch(CppSQLite3Exception& e) { e.errorCode(); } try { db.execQuery(_T("SELECT clipOrder, clipGroupOrder FROM Main")); } catch(CppSQLite3Exception& e) { if(didBackup == FALSE) didBackup = BackupDB(csPath, backupFilePrefix, &popUpMsg); db.execDML(_T("ALTER TABLE Main ADD clipOrder REAL")); db.execDML(_T("ALTER TABLE Main ADD clipGroupOrder REAL")); db.execDML(_T("Update Main set clipOrder = lDate, clipGroupOrder = lDate")); db.execDML(_T("CREATE INDEX Main_ClipOrder on Main(clipOrder DESC)")); db.execDML(_T("CREATE INDEX Main_ClipGroupOrder on Main(clipGroupOrder DESC)")); db.execDML(_T("DROP INDEX Main_Date")); e.errorCode(); } try { db.execQuery(_T("SELECT globalShortCut FROM Main")); } catch(CppSQLite3Exception& e) { if(didBackup == FALSE) didBackup = BackupDB(csPath, backupFilePrefix, &popUpMsg); db.execDML(_T("ALTER TABLE Main ADD globalShortCut INTEGER")); e.errorCode(); } try { db.execQuery(_T("SELECT lastPasteDate FROM Main")); } catch(CppSQLite3Exception& e) { if(didBackup == FALSE) didBackup = BackupDB(csPath, backupFilePrefix, &popUpMsg); db.execDML(_T("ALTER TABLE Main ADD lastPasteDate INTEGER")); db.execDML(_T("Update Main set lastPasteDate = lDate")); db.execDMLEx(_T("Update Main set lastPasteDate = %d where lastPasteDate <= 0"), (int)CTime::GetCurrentTime().GetTime()); e.errorCode(); } try { db.execQuery(_T("SELECT stickyClipOrder FROM Main")); } catch (CppSQLite3Exception& e) { if (didBackup == FALSE) didBackup = BackupDB(csPath, backupFilePrefix, &popUpMsg); db.execDML(_T("ALTER TABLE Main ADD stickyClipOrder REAL")); db.execDML(_T("ALTER TABLE Main ADD stickyClipGroupOrder REAL")); e.errorCode(); } try { CppSQLite3Query q = db.execQuery(_T("PRAGMA index_info(Main_NoGroup);")); int count = 0; while (q.eof() == false) { count++; q.nextRow(); } if(count == 0) { if (didBackup == FALSE) didBackup = BackupDB(csPath, backupFilePrefix, &popUpMsg); db.execDML(_T("Update Main set stickyClipOrder = -(2147483647) where stickyClipOrder IS NULL;")); db.execDML(_T("Update Main set stickyClipGroupOrder = -(2147483647) where stickyClipGroupOrder IS NULL;")); db.execDML(_T("Update Main set stickyClipOrder = -(2147483647) where stickyClipOrder = 0;")); db.execDML(_T("Update Main set stickyClipGroupOrder = -(2147483647) where stickyClipGroupOrder = 0;")); db.execDML(_T("CREATE INDEX Main_NoGroup ON Main(bIsGroup ASC, stickyClipOrder DESC, clipOrder DESC);")); db.execDML(_T("CREATE INDEX Main_InGroup ON Main(lParentId ASC, bIsGroup ASC, stickyClipGroupOrder DESC, clipGroupOrder DESC);")); db.execDML(_T("CREATE INDEX Data_ParentId_Format ON Data(lParentID COLLATE BINARY ASC, strClipBoardFormat COLLATE NOCASE ASC);")); } } catch (CppSQLite3Exception& e) { if (didBackup == FALSE) didBackup = BackupDB(csPath, backupFilePrefix, &popUpMsg); e.errorCode(); } } CATCH_SQLITE_EXCEPTION_AND_RETURN(FALSE) if(popUpMsg != NULL && IsWindow(popUpMsg->m_hWnd)) { popUpMsg->CloseWindow(); popUpMsg->DestroyWindow(); popUpMsg = NULL; } return TRUE; }