![]() |
Mixxx
|
00001 // schemamanager.cpp 00002 // Created 12/29/2009 by RJ Ryan (rryan@mit.edu) 00003 00004 #include <QtCore> 00005 #include <QtDebug> 00006 00007 #include "library/schemamanager.h" 00008 #include "widget/wwidget.h" 00009 00010 const QString SchemaManager::SETTINGS_VERSION_STRING = "mixxx.schema.version"; 00011 const QString SchemaManager::SETTINGS_MINCOMPATIBLE_STRING = "mixxx.schema.min_compatible_version"; 00012 00013 // static 00014 bool SchemaManager::upgradeToSchemaVersion(ConfigObject<ConfigValue>* config, 00015 QSqlDatabase& db, int targetVersion) { 00016 00017 SettingsDAO settings(db); 00018 int currentVersion = getCurrentSchemaVersion(settings); 00019 Q_ASSERT(currentVersion >= 0); 00020 00021 if (currentVersion == targetVersion) { 00022 qDebug() << "SchemaManager::upgradeToSchemaVersion already at version" 00023 << targetVersion; 00024 return true; 00025 } else if (currentVersion < targetVersion) { 00026 qDebug() << "SchemaManager::upgradeToSchemaVersion upgrading" 00027 << targetVersion-currentVersion << "versions to version" 00028 << targetVersion; 00029 } else { 00030 qDebug() << "SchemaManager::upgradeToSchemaVersion already past target " 00031 "version. currentVersion:" 00032 << currentVersion << "targetVersion:" 00033 << targetVersion; 00034 00035 if (isBackwardsCompatible(settings, currentVersion, targetVersion)) { 00036 qDebug() << "Current schema version is backwards-compatible with" << targetVersion; 00037 return true; 00038 } 00039 } 00040 00041 QString schemaFilename = config->getConfigPath(); 00042 schemaFilename.append("schema.xml"); 00043 qDebug() << "Loading schema" << schemaFilename; 00044 QDomElement schemaRoot = WWidget::openXMLFile(schemaFilename, "schema"); 00045 00046 QDomNodeList revisions = schemaRoot.childNodes(); 00047 00048 QMap<int, QDomElement> revisionMap; 00049 00050 for (int i = 0; i < revisions.count(); i++) { 00051 QDomElement revision = revisions.at(i).toElement(); 00052 QString version = revision.attribute("version"); 00053 Q_ASSERT(!version.isNull()); 00054 int iVersion = version.toInt(); 00055 revisionMap[iVersion] = revision; 00056 } 00057 00058 bool success = true; 00059 00060 while (currentVersion != targetVersion) { 00061 int thisTarget; 00062 if (currentVersion > targetVersion) { 00063 thisTarget = currentVersion - 1; 00064 qDebug() << "Downgrade not yet supported."; 00065 success = false; 00066 break; 00067 } else { 00068 thisTarget = currentVersion + 1; 00069 } 00070 00071 if (!revisionMap.contains(thisTarget)) { 00072 qDebug() << "SchemaManager::upgradeToSchemaVersion" 00073 << "Don't know how to get to" 00074 << thisTarget << "from" << currentVersion; 00075 success = false; 00076 break; 00077 } 00078 00079 QDomElement revision = revisionMap[thisTarget]; 00080 QDomElement eDescription = revision.firstChildElement("description"); 00081 QDomElement eSql = revision.firstChildElement("sql"); 00082 QString minCompatibleVersion = revision.attribute("min_compatible"); 00083 00084 // Default the min-compatible version to the current version string if 00085 // it's not in the schema.xml 00086 if (minCompatibleVersion.isNull()) { 00087 minCompatibleVersion = QString::number(thisTarget); 00088 } 00089 00090 Q_ASSERT(!eDescription.isNull() && !eSql.isNull()); 00091 00092 QString description = eDescription.text(); 00093 QString sql = eSql.text(); 00094 00095 00096 qDebug() << "Applying version" << thisTarget << ":" 00097 << description.trimmed(); 00098 00099 db.transaction(); 00100 00101 // TODO(XXX) We can't have semicolons in schema.xml for anything other 00102 // than statement separators. 00103 QStringList sqlStatements = sql.split(";"); 00104 00105 QStringListIterator it(sqlStatements); 00106 00107 QSqlQuery query(db); 00108 bool result = true; 00109 while (result && it.hasNext()) { 00110 QString statement = it.next().trimmed(); 00111 if (statement.isEmpty()) { 00112 continue; 00113 } 00114 result = result && query.exec(statement); 00115 if (!result) { 00116 qDebug() << "Failed query:" 00117 << statement 00118 << query.lastError(); 00119 } 00120 } 00121 00122 if (result) { 00123 currentVersion = thisTarget; 00124 settings.setValue(SETTINGS_VERSION_STRING, thisTarget); 00125 settings.setValue(SETTINGS_MINCOMPATIBLE_STRING, minCompatibleVersion); 00126 db.commit(); 00127 } else { 00128 success = false; 00129 qDebug() << "Failed to move from version" << currentVersion 00130 << "to version" << thisTarget; 00131 db.rollback(); 00132 break; 00133 } 00134 } 00135 00136 return success; 00137 } 00138 00139 // static 00140 int SchemaManager::getCurrentSchemaVersion(SettingsDAO& settings) { 00141 QString currentSchemaVersion = settings.getValue(SETTINGS_VERSION_STRING); 00142 // May be a null string if the schema has not been created. We default the 00143 // startVersion to 0 so that we automatically try to upgrade to revision 1. 00144 int currentVersion = 0; 00145 if (!currentSchemaVersion.isNull()) { 00146 currentVersion = currentSchemaVersion.toInt(); 00147 } 00148 return currentVersion; 00149 } 00150 00151 // static 00152 bool SchemaManager::isBackwardsCompatible(SettingsDAO& settings, 00153 int currentVersion, 00154 int targetVersion) { 00155 QString backwardsCompatibleVersion = 00156 settings.getValue(SETTINGS_MINCOMPATIBLE_STRING); 00157 int iBackwardsCompatibleVersion = -1; 00158 00159 // If the current backwards compatible schema version is not stored in the 00160 // settings table, assume the current schema version is only backwards 00161 // compatible with itself. 00162 if (backwardsCompatibleVersion.isNull()) { 00163 // rryan 11/2010 We just added the backwards compatible flags, and some 00164 // people using the Mixxx trunk are already on schema version 7. This 00165 // special case is for them. Schema version 7 is backwards compatible 00166 // with schema version 3. 00167 if (currentVersion == 7) { 00168 iBackwardsCompatibleVersion = 3; 00169 } else { 00170 iBackwardsCompatibleVersion = currentVersion; 00171 } 00172 } 00173 00174 // If the target version is greater than the minimum compatible version of 00175 // the current schema, then the current schema is backwards compatible with 00176 // targetVersion. 00177 return iBackwardsCompatibleVersion <= targetVersion; 00178 }