Commit b169e845 authored by Hugo Beauzée-Luyssen's avatar Hugo Beauzée-Luyssen
Browse files

Remove old migrations

Fix #217
parent 22e3ab4f
Pipeline #145176 passed with stages
in 4 minutes and 17 seconds
......@@ -186,17 +186,6 @@ std::string Device::schema( const std::string& tableName, uint32_t dbModel )
")";
}
assert( tableName == Table::Name );
if ( dbModel <= 13 )
{
return "CREATE TABLE " + Device::Table::Name +
"("
"id_device INTEGER PRIMARY KEY AUTOINCREMENT,"
"uuid TEXT UNIQUE ON CONFLICT FAIL,"
"scheme TEXT,"
"is_removable BOOLEAN,"
"is_present BOOLEAN"
")";
}
if ( dbModel < 24 )
{
return "CREATE TABLE " + Device::Table::Name +
......
......@@ -825,17 +825,6 @@ const std::string&Folder::name() const
return m_name;
}
void Folder::setName( std::string name )
{
assert( m_name.empty() == true );
static const std::string req = "UPDATE " + Table::Name +
" SET name = ? WHERE id_folder = ?";
auto dbConn = m_ml->getConn();
if ( sqlite::Tools::executeUpdate( dbConn, req, name, m_id ) == false )
return;
m_name = std::move( name );
}
const std::string& Folder::rawMrl() const
{
return m_path;
......
......@@ -145,8 +145,6 @@ public:
virtual int64_t id() const override;
virtual const std::string& mrl() const override;
virtual const std::string& name() const override;
// Used for 13 -> 14 migration
void setName( std::string name );
const std::string& rawMrl() const;
void setMrl( std::string mrl );
std::vector<std::shared_ptr<File>> files();
......
......@@ -1194,97 +1194,13 @@ InitializeResult MediaLibrary::updateDatabaseModel( unsigned int previousVersion
// In case of downgrade, just recreate the database
// We might also have some special cases for failed upgrade (see
// comments below for per-version details)
if ( previousVersion < 3 ||
previousVersion > Settings::DbModelVersion ||
previousVersion == 4 )
if ( previousVersion < 15 ||
previousVersion > Settings::DbModelVersion )
{
if( recreateDatabase() == false )
throw std::runtime_error( "Failed to recreate the database" );
return InitializeResult::DbReset;
}
/**
* Migration from 3 to 4 didn't happen so well and broke a few
* users DB. So:
* - Any v4 database will be dropped and recreated in v5
* - Any v3 database will be upgraded to v5
* V4 database is only used by VLC-android 2.5.6 // 2.5.8, which are
* beta versions.
*/
if ( previousVersion == 3 )
{
migrateModel3to5();
previousVersion = 5;
}
if ( previousVersion == 5 )
{
migrateModel5to6();
previousVersion = 6;
}
if ( previousVersion == 6 )
{
// Force a rescan to solve metadata analysis problems.
// The insertion is fixed, but won't edit already inserted data.
needRescan = true;
previousVersion = 7;
}
/**
* V7 introduces artist.nb_tracks and an associated trigger to delete
* artists when it has no track/album left.
*/
if ( previousVersion == 7 )
{
migrateModel7to8();
previousVersion = 8;
}
if ( previousVersion == 8 )
{
// Multiple changes justify the rescan:
// - Changes in the way we chose to encode or not MRL, meaning
// potentially all MRL are wrong (more precisely, will
// mismatch what VLC expects, which makes playlist analysis
// break.
// - Fix in the way we chose album candidates, meaning some
// albums were likely to be wrongfully created.
needRescan = true;
migrateModel8to9();
previousVersion = 9;
}
if ( previousVersion == 9 )
{
needRescan = true;
migrateModel9to10();
previousVersion = 10;
}
if ( previousVersion == 10 )
{
needRescan = true;
migrateModel10to11();
previousVersion = 11;
}
if ( previousVersion == 11 )
{
parser::Task::recoverUnscannedFiles( this );
previousVersion = 12;
}
if ( previousVersion == 12 )
{
migrateModel12to13();
previousVersion = 13;
}
if ( previousVersion == 13 )
{
// We need to recreate many thumbnail records, and hopefully
// generate better ones
needRescan = true;
migrateModel13to14( originalPreviousVersion );
previousVersion = 14;
}
if ( previousVersion == 14 )
{
migrateModel14to15();
previousVersion = 15;
}
if ( previousVersion == 15 )
{
migrateModel15to16();
......@@ -1468,276 +1384,6 @@ bool MediaLibrary::recreateDatabase()
return checkDatabaseIntegrity();
}
void MediaLibrary::migrateModel3to5()
{
/*
* Disable Foreign Keys & recursive triggers to avoid cascading deletion
* while remodeling the database into the transaction.
*/
sqlite::Connection::WeakDbContext weakConnCtx{ getConn() };
auto t = getConn()->newTransaction();
// As SQLite do not allow us to remove or add some constraints,
// we use the method described here https://www.sqlite.org/faq.html#q11
std::string reqs[] = {
# include "database/migrations/migration3-5.sql"
};
for ( const auto& req : reqs )
sqlite::Tools::executeRequest( getConn(), req );
m_settings.setDbModelVersion( 5 );
t->commit();
}
void MediaLibrary::migrateModel5to6()
{
// We can't create a transaction here since it would make the weak context
// creation fail.
std::string req = "DELETE FROM " + Media::Table::Name + " WHERE type = ?";
sqlite::Tools::executeRequest( getConn(), req, Media::Type::Unknown );
sqlite::Connection::WeakDbContext weakConnCtx{ getConn() };
req = "UPDATE " + Media::Table::Name + " SET is_present = 1 WHERE is_present != 0";
sqlite::Tools::executeRequest( getConn(), req );
m_settings.setDbModelVersion( 6 );
}
void MediaLibrary::migrateModel7to8()
{
sqlite::Connection::WeakDbContext weakConnCtx{ getConn() };
auto t = getConn()->newTransaction();
std::string reqs[] = {
parser::Task::schema( parser::Task::Table::Name, 8 ),
# include "database/migrations/migration7-8.sql"
};
for ( const auto& req : reqs )
sqlite::Tools::executeRequest( getConn(), req );
// Re-create triggers removed in the process
m_settings.setDbModelVersion( 8 );
t->commit();
}
bool MediaLibrary::migrateModel8to9()
{
// A bug in a previous migration caused our triggers to be missing for the
// first application run (after the migration).
// This could have caused media associated to deleted files not to be
// deleted as well, so let's do that now.
auto t = getConn()->newTransaction();
const std::string req = "DELETE FROM " + Media::Table::Name + " "
"WHERE id_media IN "
"(SELECT id_media FROM " + Media::Table::Name + " m LEFT JOIN " +
File::Table::Name + " f ON f.media_id = m.id_media "
"WHERE f.media_id IS NULL)";
if ( sqlite::Tools::executeDelete( getConn(), req ) == false )
return false;
m_settings.setDbModelVersion( 9 );
t->commit();
return false;
}
void MediaLibrary::migrateModel9to10()
{
const std::string req = "SELECT * FROM " + File::Table::Name +
" WHERE mrl LIKE '%#%%' ESCAPE '#'";
auto files = File::fetchAll<File>( this, req );
auto t = getConn()->newTransaction();
for ( const auto& f : files )
{
// We must not call mrl() from here. We might not have all devices yet,
// and calling mrl would crash for files stored on removable devices.
auto newMrl = utils::url::encode( utils::url::decode( f->rawMrl() ) );
LOG_DEBUG( "Converting ", f->rawMrl(), " to ", newMrl );
f->setMrl( std::move( newMrl ) );
}
m_settings.setDbModelVersion( 10 );
t->commit();
}
void MediaLibrary::migrateModel10to11()
{
// Now empty because migration 15 to 16 is doing the same thing again
// We updated the MRL encoding in 10 to 11, but again from 15 to 16, so we
// might as well re encode everything only once.
m_settings.setDbModelVersion( 11 );
}
/*
* - Some is_present related triggers were fixed in model 6 to 7 migration, but
* they were not recreated if already existing. The has_file_present trigger
* was recreated as part of model 7 to 8 migration, but we need to ensure
* has_album_present (Artist) & is_album_present (Album) triggers are
* recreated to behave as expected
* - Due to a typo, is_track_present was named is_track_presentAFTER, and was
* executed BEFORE the update took place, thus using the wrong is_present value.
* The trigger will be recreated as part of this migration, and the values
* will be enforced, causing the entire update chain to be triggered, and
* restoring correct is_present values for all AlbumTrack/Album/Artist entries
*/
bool MediaLibrary::migrateModel12to13()
{
auto t = getConn()->newTransaction();
const std::string reqs[] = {
"DROP TRIGGER IF EXISTS is_track_presentAFTER",
"DROP TRIGGER has_album_present",
"DROP TRIGGER is_album_present",
Album::trigger( Album::Triggers::IsPresent, 13 ),
Artist::trigger( Artist::Triggers::HasTrackPresent, 13 ),
};
for ( const auto& req : reqs )
{
if ( sqlite::Tools::executeDelete( getConn(), req ) == false )
return false;
}
// Leave the weak context as we now need to update is_present fields, which
// are propagated through recursive triggers
const std::string migrateData = "UPDATE " + AlbumTrack::Table::Name +
" SET is_present = (SELECT is_present FROM " + Media::Table::Name +
" WHERE id_media = media_id)";
if ( sqlite::Tools::executeUpdate( getConn(), migrateData ) == false )
return false;
m_settings.setDbModelVersion( 13 );
t->commit();
return true;
}
/*
* Model v13 to v14 migration:
* - Media:
* - Remove
* .thumbnail
* .
* - Add
* .nb_playlists
* .real_last_played_date
* .device_id
* .folder_id
* - Fix filename being url encoded
* - Fix playlist external media type being Unknown
* - Playlist:
* - Add .file_id
* - PlaylistMediaRelation:
* - Add .mrl
* - Add a playlist FTS table
* - Add Thumbnail table
* - Task:
* - Add .is_refresh
* - Device:
* - Add last_seen
* - Folder:
* - Add:
* .nb_audio
* .nb_video
* - Remove .is_present
* - Rename is_blacklisted to is_banned
* _ Add a Folder FTS table
* - File:
* - Add .is_network
* - Remove .is_present
* - Add SubtitleTrack table
* - Removed History table
* - Removed on_track_genre_changed trigger
* - Removed is_folder_present trigger
* - Removed has_files_present trigger
* - Removed is_device_present trigger
* - Update is_album_present trigger
* - Update add_album_track trigger
* - Update delete_album_track trigger
* - New chapters table
*/
void MediaLibrary::migrateModel13to14( uint32_t originalPreviousVersion )
{
auto dbConn = getConn();
sqlite::Connection::WeakDbContext weakConnCtx{ dbConn };
auto t = dbConn->newTransaction();
SubtitleTrack::createTable( dbConn );
SubtitleTrack::createIndexes( dbConn );
Chapter::createTable( dbConn );
std::string reqs[] = {
# include "database/migrations/migration13-14.sql"
Thumbnail::schema( Thumbnail::Table::Name, 14 ),
};
for ( const auto& req : reqs )
sqlite::Tools::executeRequest( dbConn, req );
// Task table was introduced in model 8, so if the user is migrating from a
// version earlier than this one, the Task table will be properly created and
// doesn't need a migration
if ( originalPreviousVersion >= 8 )
{
const std::string migrateTaskReqs[] = {
"CREATE TEMPORARY TABLE " + parser::Task::Table::Name + "_backup"
"("
"id_task INTEGER PRIMARY KEY AUTOINCREMENT,"
"step INTEGER NOT NULL DEFAULT 0,"
"retry_count INTEGER NOT NULL DEFAULT 0,"
"mrl TEXT,"
"file_id UNSIGNED INTEGER,"
"parent_folder_id UNSIGNED INTEGER,"
"parent_playlist_id INTEGER,"
"parent_playlist_index UNSIGNED INTEGER"
")",
"INSERT INTO " + parser::Task::Table::Name + "_backup SELECT * FROM " + parser::Task::Table::Name,
"DROP TABLE " + parser::Task::Table::Name,
parser::Task::schema( parser::Task::Table::Name, 14 ),
"INSERT INTO " + parser::Task::Table::Name + " SELECT "
"id_task, step, retry_count, mrl, " +
std::to_string( static_cast<std::underlying_type<IFile::Type>::type>(
IFile::Type::Main ) ) + ","
"file_id, parent_folder_id, parent_playlist_id,"
"parent_playlist_index, 0 FROM " + parser::Task::Table::Name + "_backup",
"DROP TABLE " + parser::Task::Table::Name + "_backup",
};
for ( const auto& req : migrateTaskReqs )
sqlite::Tools::executeRequest( dbConn, req );
}
// Re-create tables that we just removed
// We will run a re-scan, so we don't care about keeping their content
std::string recreateReqs[] = {
Album::schema( Album::Table::Name, 14 ),
Artist::schema( Artist::Table::Name, 14 ),
};
for ( const auto& req : recreateReqs )
sqlite::Tools::executeRequest( dbConn, req );
Show::createTable( dbConn );
VideoTrack::createTable( dbConn );
auto folders = Folder::fetchAll<Folder>( this );
for ( const auto& f : folders )
{
f->setName( utils::file::directoryName( f->rawMrl() ) );
}
m_settings.setDbModelVersion( 14 );
t->commit();
}
/**
* Model 14 to 15 migration:
* - Folder.name is now case insensitive
*/
void MediaLibrary::migrateModel14to15()
{
auto dbConn = getConn();
sqlite::Connection::WeakDbContext weakConnCtx{ dbConn };
auto t = dbConn->newTransaction();
std::string reqs[] = {
# include "database/migrations/migration14-15.sql"
};
for ( const auto& req : reqs )
sqlite::Tools::executeRequest( dbConn, req );
m_settings.setDbModelVersion( 15 );
t->commit();
}
/**
* Model 15 to 16 migration:
* - Remove update_playlist_order trigger
......
......@@ -290,15 +290,6 @@ protected:
private:
bool recreateDatabase();
InitializeResult updateDatabaseModel( unsigned int previousVersion );
void migrateModel3to5();
void migrateModel5to6();
void migrateModel7to8();
bool migrateModel8to9();
void migrateModel9to10();
void migrateModel10to11();
bool migrateModel12to13();
void migrateModel13to14( uint32_t originalPreviousVersion );
void migrateModel14to15();
void migrateModel15to16();
void migrateModel16to17();
void migrateModel17to18(uint32_t originalPreviousVersion);
......
......@@ -213,17 +213,10 @@ void Metadata::createTable(sqlite::Connection* connection)
std::string Metadata::schema( const std::string& tableName, uint32_t dbModel )
{
UNUSED_IN_RELEASE( tableName );
UNUSED_IN_RELEASE( dbModel );
assert( tableName == Table::Name );
if ( dbModel < 14 )
{
return "CREATE TABLE " + Table::Name +
"("
"id_media INTEGER,"
"type INTEGER,"
"value TEXT"
")";
}
assert( dbModel >= 14 );
return "CREATE TABLE " + Table::Name +
"("
"id_media INTEGER,"
......
/******************* Migrate Media table **************************************/
"CREATE TEMPORARY TABLE " + Media::Table::Name + "_backup("
"id_media INTEGER PRIMARY KEY AUTOINCREMENT,"
"type INTEGER,"
"subtype INTEGER,"
"duration INTEGER DEFAULT -1,"
"play_count UNSIGNED INTEGER,"
"last_played_date UNSIGNED INTEGER,"
"insertion_date UNSIGNED INTEGER,"
"release_date UNSIGNED INTEGER,"
"thumbnail TEXT,"
"title TEXT COLLATE NOCASE,"
"filename TEXT,"
"is_favorite BOOLEAN NOT NULL DEFAULT 0,"
"is_present BOOLEAN NOT NULL DEFAULT 1"
")",
"INSERT INTO " + Media::Table::Name + "_backup SELECT * FROM " + Media::Table::Name,
"DROP TABLE " + Media::Table::Name,
Media::schema( Media::Table::Name, 14 ),
"INSERT INTO " + Media::Table::Name + "("
"id_media, type, subtype, duration, play_count, last_played_date, real_last_played_date, insertion_date,"
"release_date, thumbnail_id, title, filename, is_favorite,"
"is_present) "
"SELECT id_media, type, ifnull(subtype, " +
std::to_string( static_cast<typename std::underlying_type<IMedia::SubType>::type>(
IMedia::SubType::Unknown ) )
+ "), duration, play_count, last_played_date,"
"strftime('%s', 'now'),"
"insertion_date, release_date, 0,"
"title, filename, is_favorite, is_present FROM " + Media::Table::Name + "_backup",
"DROP TABLE " + Media::Table::Name + "_backup",
/******************* Populate new media.nb_playlists **************************/
"UPDATE " + Media::Table::Name + " SET nb_playlists = "
"(SELECT COUNT(media_id) FROM " + Playlist::MediaRelationTable::Name +
" WHERE media_id = id_media )"
"WHERE id_media IN (SELECT media_id FROM " + Playlist::MediaRelationTable::Name + ")",
/*************** Populate new media.device_id & folder_id *********************/
"UPDATE " + Media::Table::Name + " SET (device_id, folder_id) = "
"(SELECT d.id_device, f.id_folder FROM " + Device::Table::Name + " d "
"INNER JOIN " + Folder::Table::Name + " f ON d.id_device = f.device_id "
"INNER JOIN " + File::Table::Name + " fi ON fi.folder_id = f.id_folder "
"WHERE fi.type = " +
std::to_string( static_cast<typename std::underlying_type<IFile::Type>::type>(
IFile::Type::Main) ) + " "
"AND fi.media_id = " + Media::Table::Name + ".id_media"
")",
/************ Playlist external media were stored as Unknown ******************/
/* External type was removed in model 23 but used to be equal to 3 */
"UPDATE " + Media::Table::Name + " SET type = 3 "
"WHERE nb_playlists > 0 AND "
"type = " + std::to_string( static_cast<typename std::underlying_type<IMedia::Type>::type>(
IMedia::Type::Unknown ) ),
/******************* Migrate metadata table ***********************************/
"CREATE TEMPORARY TABLE " + Metadata::Table::Name + "_backup"
"("
"id_media INTEGER,"
"type INTEGER,"
"value TEXT"
")",
"INSERT INTO " + Metadata::Table::Name + "_backup SELECT * FROM MediaMetadata",
"DROP TABLE MediaMetadata",
// Recreate the new table
Metadata::schema( Metadata::Table::Name, 14 ),
"INSERT INTO " + Metadata::Table::Name + " "
"SELECT "
"id_media, " + std::to_string(
static_cast<typename std::underlying_type<IMetadata::EntityType>::type>(
IMetadata::EntityType::Media ) ) +
", type, value "
"FROM " + Metadata::Table::Name + "_backup",
"DROP TABLE " + Metadata::Table::Name + "_backup",
/******************* Migrate the playlist table *******************************/
"CREATE TEMPORARY TABLE " + Playlist::Table::Name + "_backup"
"("
+ Playlist::Table::PrimaryKeyColumn + " INTEGER PRIMARY KEY AUTOINCREMENT,"
"name TEXT,"
"file_id UNSIGNED INT DEFAULT NULL,"
"creation_date UNSIGNED INT NOT NULL,"
"artwork_mrl TEXT"
")",
"CREATE TEMPORARY TABLE " + Playlist::MediaRelationTable::Name + "_backup"
"("
"media_id INTEGER,"
"playlist_id INTEGER,"
"position INTEGER"
")",
"INSERT INTO " + Playlist::Table::Name + "_backup SELECT * FROM " + Playlist::Table::Name,
"INSERT INTO " + Playlist::MediaRelationTable::Name + "_backup SELECT * FROM " + Playlist::MediaRelationTable::Name,
"DROP TABLE " + Playlist::Table::Name,
"DROP TABLE " + Playlist::MediaRelationTable::Name,
Playlist::schema( Playlist::Table::Name, 14 ),
Playlist::schema( Playlist::MediaRelationTable::Name, 14 ),
"INSERT INTO " + Playlist::Table::Name + " SELECT * FROM " + Playlist::Table::Name + "_backup",
"INSERT INTO " + Playlist::MediaRelationTable::Name + " SELECT media_id, NULL, playlist_id, position "
"FROM " + Playlist::MediaRelationTable::Name + "_backup",
"DROP TABLE " + Playlist::Table::Name + "_backup",
"DROP TABLE " + Playlist::MediaRelationTable::Name + "_backup",
/******************* Migrate Device table *************************************/
"CREATE TEMPORARY TABLE " + Device::Table::Name + "_backup"
"("
"id_device INTEGER PRIMARY KEY AUTOINCREMENT,"
"uuid TEXT UNIQUE ON CONFLICT FAIL,"
"scheme TEXT,"
"is_removable BOOLEAN,"
"is_present BOOLEAN"
")",
"INSERT INTO " + Device::Table::Name + "_backup SELECT * FROM " + Device::Table::Name,
"DROP TABLE " + Device::Table::Name,
Device::schema( Device::Table::Name, 14 ),
"INSERT INTO " + Device::Table::Name + " SELECT id_device, uuid, scheme, is_removable, is_present,"
"strftime('%s', 'now') FROM " + Device::Table::Name + "_backup",
"DROP TABLE " + Device::Table::Name + "_backup",
/******************* Migrate Folder table *************************************/
"CREATE TEMPORARY TABLE " + Folder::Table::Name + "_backup"
"("
"id_folder INTEGER PRIMARY KEY AUTOINCREMENT,"
"path TEXT,"