Browse Source

Change db migration patterns to always increase db version regardless of function logic outcome.

This change will make it clearer to not place the version increase dependent on any logic flow outcome which would create an infinite loop in the callee as found during unit tests.
tags/release_0.25.1
JackDandy 5 years ago
parent
commit
e1f6de0ca4
  1. 1
      CHANGES.md
  2. 5
      sickbeard/databases/cache_db.py
  3. 2
      sickbeard/databases/failed_db.py
  4. 81
      sickbeard/databases/mainDB.py
  5. 4
      sickbeard/db.py
  6. 64
      tests/migration_tests.py

1
CHANGES.md

@ -89,6 +89,7 @@
* Replace Telegram notififier "Send icon" with "Send show image"
* Add Telegram notifier option "Send quietly" to mute client notification sound
* Fix AddIndexerToTables function used for tests
* Change db migration patterns to always increase db version regardless of function logic outcome
### 0.21.37 (2020-05-30 12:00:00 UTC)

5
sickbeard/databases/cache_db.py

@ -77,7 +77,7 @@ class InitialSchema(db.SchemaUpgrade):
def execute(self):
self.do_query(self.queries[next(iter(self.queries))])
self.setDBVersion(MIN_DB_VERSION)
self.setDBVersion(MIN_DB_VERSION, check_db_version=False)
class ConsolidateProviders(InitialSchema):
@ -130,5 +130,4 @@ class AddGenericFailureHandling(AddBacklogParts):
def execute(self):
self.do_query(self.queries['connection_fails'])
self.setDBVersion(100001)
#self.finish()
self.setDBVersion(100001, check_db_version=False)

2
sickbeard/databases/failed_db.py

@ -103,4 +103,4 @@ class AddIndexerToTables(HistoryStatus):
self.connection.action('VACUUM')
self.setDBVersion(2)
self.setDBVersion(2, check_db_version=False)

81
sickbeard/databases/mainDB.py

@ -714,8 +714,7 @@ class AddProperNamingSupport(db.SchemaUpgrade):
if not self.hasColumn('tv_shows', 'imdb_id')\
and self.hasColumn('tv_shows', 'rls_require_words')\
and self.hasColumn('tv_shows', 'rls_ignore_words'):
self.setDBVersion(5816)
return self.checkDBVersion()
return self.setDBVersion(5816)
if not self.hasColumn('tv_episodes', 'is_proper'):
self.upgrade_log(u'Adding column is_proper to tv_episodes')
@ -734,8 +733,7 @@ class AddEmailSubscriptionTable(db.SchemaUpgrade):
and self.hasColumn('tv_shows', 'rls_require_words')\
and self.hasColumn('tv_shows', 'rls_ignore_words')\
and self.hasColumn('tv_shows', 'skip_notices'):
self.setDBVersion(5817)
return self.checkDBVersion()
return self.setDBVersion(5817)
if not self.hasColumn('tv_shows', 'notify_list'):
self.upgrade_log(u'Adding column notify_list to tv_shows')
@ -750,16 +748,14 @@ class AddEmailSubscriptionTable(db.SchemaUpgrade):
class AddProperSearch(db.SchemaUpgrade):
def execute(self):
if not self.hasColumn('tv_episodes', 'is_proper'):
self.setDBVersion(12)
return self.checkDBVersion()
return self.setDBVersion(12)
if not self.hasColumn('tv_shows', 'notify_list')\
and self.hasColumn('tv_shows', 'rls_require_words')\
and self.hasColumn('tv_shows', 'rls_ignore_words')\
and self.hasColumn('tv_shows', 'skip_notices')\
and self.hasColumn('history', 'source'):
self.setDBVersion(5818)
return self.checkDBVersion()
return self.setDBVersion(5818)
if not self.hasColumn('info', 'last_proper_search'):
self.upgrade_log(u'Adding column last_proper_search to info')
@ -1179,8 +1175,7 @@ class BumpDatabaseVersion(db.SchemaUpgrade):
self.upgrade_log(u'Bumping database version')
self.setDBVersion(10000)
return self.checkDBVersion()
return self.setDBVersion(10000)
# 41,42 -> 10001
@ -1190,8 +1185,7 @@ class Migrate41(db.SchemaUpgrade):
self.upgrade_log(u'Bumping database version')
self.setDBVersion(10001)
return self.checkDBVersion()
return self.setDBVersion(10001)
# 43,44 -> 10001
@ -1227,8 +1221,7 @@ class Migrate43(db.SchemaUpgrade):
if not db_chg:
self.upgrade_log(u'Bumping database version')
self.setDBVersion(10001)
return self.checkDBVersion()
return self.setDBVersion(10001)
# 4301 -> 10002
@ -1238,8 +1231,7 @@ class Migrate4301(db.SchemaUpgrade):
self.upgrade_log(u'Bumping database version')
self.setDBVersion(10002)
return self.checkDBVersion()
return self.setDBVersion(10002)
# 4302,4400 -> 10003
@ -1249,8 +1241,7 @@ class Migrate4302(db.SchemaUpgrade):
self.upgrade_log(u'Bumping database version')
self.setDBVersion(10003)
return self.checkDBVersion()
return self.setDBVersion(10003)
# 5816 - 5818 -> 15
@ -1260,8 +1251,7 @@ class MigrateUpstream(db.SchemaUpgrade):
self.upgrade_log(u'Migrate SickBeard db v%s into v15' % str(self.checkDBVersion()).replace('58', ''))
self.setDBVersion(15)
return self.checkDBVersion()
return self.setDBVersion(15)
# 10000 -> 20000
@ -1271,8 +1261,7 @@ class SickGearDatabaseVersion(db.SchemaUpgrade):
self.upgrade_log(u'Bumping database version to new SickGear standards')
self.setDBVersion(20000)
return self.checkDBVersion()
return self.setDBVersion(20000)
# 10001 -> 10000
@ -1283,8 +1272,7 @@ class RemoveDefaultEpStatusFromTvShows(db.SchemaUpgrade):
self.upgrade_log(u'Dropping redundant column default_ep_status from tv_shows')
self.dropColumn('tv_shows', 'default_ep_status')
self.setDBVersion(10000)
return self.checkDBVersion()
return self.setDBVersion(10000)
# 10002 -> 10001
@ -1295,8 +1283,7 @@ class RemoveMinorDBVersion(db.SchemaUpgrade):
self.upgrade_log(u'Dropping redundant column db_minor_version from db_version')
self.dropColumn('db_version', 'db_minor_version')
self.setDBVersion(10001)
return self.checkDBVersion()
return self.setDBVersion(10001)
# 10003 -> 10002
@ -1307,8 +1294,7 @@ class RemoveMetadataSub(db.SchemaUpgrade):
db.backup_database('sickbeard.db', self.checkDBVersion())
self.dropColumn('tv_shows', 'sub_use_sr_metadata')
self.setDBVersion(10002)
return self.checkDBVersion()
return self.setDBVersion(10002)
# 20000 -> 20001
@ -1321,8 +1307,7 @@ class DBIncreaseTo20001(db.SchemaUpgrade):
self.connection.action('VACUUM')
self.upgrade_log(u'Performed a vacuum on the database', logger.DEBUG)
self.setDBVersion(20001)
return self.checkDBVersion()
return self.setDBVersion(20001)
# 20001 -> 20002
@ -1333,8 +1318,7 @@ class AddTvShowOverview(db.SchemaUpgrade):
db.backup_database('sickbeard.db', self.checkDBVersion())
self.addColumn('tv_shows', 'overview', 'TEXT', '')
self.setDBVersion(20002)
return self.checkDBVersion()
return self.setDBVersion(20002)
# 20002 -> 20003
@ -1346,8 +1330,7 @@ class AddTvShowTags(db.SchemaUpgrade):
db.backup_database('sickbeard.db', self.checkDBVersion())
self.addColumn('tv_shows', 'tag', 'TEXT', 'Show List')
self.setDBVersion(20003)
return self.checkDBVersion()
return self.setDBVersion(20003)
# 20003 -> 20004
@ -1408,8 +1391,7 @@ class ChangeMapIndexer(db.SchemaUpgrade):
self.connection.action('VACUUM')
self.setDBVersion(20004)
return self.checkDBVersion()
return self.setDBVersion(20004)
# 20004 -> 20005
@ -1424,8 +1406,7 @@ class AddShowNotFoundCounter(db.SchemaUpgrade):
' fail_count NUMERIC NOT NULL DEFAULT 0, last_check NUMERIC NOT NULL, last_success NUMERIC,'
' PRIMARY KEY (indexer_id, indexer))')
self.setDBVersion(20005)
return self.checkDBVersion()
return self.setDBVersion(20005)
# 20005 -> 20006
@ -1437,8 +1418,7 @@ class AddFlagTable(db.SchemaUpgrade):
db.backup_database('sickbeard.db', self.checkDBVersion())
self.connection.action('CREATE TABLE flags (flag PRIMARY KEY NOT NULL )')
self.setDBVersion(20006)
return self.checkDBVersion()
return self.setDBVersion(20006)
# 20006 -> 20007
@ -1447,8 +1427,7 @@ class DBIncreaseTo20007(db.SchemaUpgrade):
self.upgrade_log(u'Bumping database version')
self.setDBVersion(20007)
return self.checkDBVersion()
return self.setDBVersion(20007)
# 20007 -> 20008
@ -1457,8 +1436,7 @@ class AddWebdlTypesTable(db.SchemaUpgrade):
db.backup_database('sickbeard.db', self.checkDBVersion())
self.connection.action('CREATE TABLE webdl_types (dname TEXT NOT NULL , regex TEXT NOT NULL )')
self.setDBVersion(20008)
return self.checkDBVersion()
return self.setDBVersion(20008)
# 20008 -> 20009
@ -1479,8 +1457,7 @@ class AddWatched(db.SchemaUpgrade):
' status NUMERIC, location TEXT, file_size NUMERIC, hide INT default 0 not null)'
)
self.setDBVersion(20009)
return self.checkDBVersion()
return self.setDBVersion(20009)
# 20009 -> 20010
@ -1493,8 +1470,7 @@ class AddPrune(db.SchemaUpgrade):
db.backup_database('sickbeard.db', self.checkDBVersion())
self.addColumn('tv_shows', 'prune', 'INT', 0)
self.setDBVersion(20010)
return self.checkDBVersion()
return self.setDBVersion(20010)
# 20010 -> 20011
@ -1643,8 +1619,7 @@ class AddIndexerToTables(db.SchemaUpgrade):
self.connection.action('VACUUM')
self.setDBVersion(20011)
return self.checkDBVersion()
return self.setDBVersion(20011)
# 20011 -> 20012
@ -1671,8 +1646,7 @@ class AddShowExludeGlobals(db.SchemaUpgrade):
['DROP TABLE tv_shows_exclude_backup']
])
self.setDBVersion(20012)
return self.checkDBVersion()
return self.setDBVersion(20012)
# 20012 -> 20013
@ -1693,5 +1667,4 @@ class RenameAllowBlockListTables(db.SchemaUpgrade):
['DROP TABLE tmp_%slist' % new]
])
self.setDBVersion(20013)
return self.checkDBVersion()
return self.setDBVersion(20013)

4
sickbeard/db.py

@ -516,10 +516,10 @@ class SchemaUpgrade(object):
self.connection.action('UPDATE db_version SET db_version = ? WHERE 1=1', [new_version])
return new_version
def setDBVersion(self, new_version):
def setDBVersion(self, new_version, check_db_version=True):
# noinspection SqlConstantCondition
self.connection.action('UPDATE db_version SET db_version = ? WHERE 1=1', [new_version])
return new_version
return check_db_version and self.checkDBVersion()
def listTables(self):
tables = []

64
tests/migration_tests.py

@ -22,7 +22,8 @@ class MigrationBasicTests(test.SickbeardTestDBCase):
def tearDown(self):
pass
def test_migrations(self):
@staticmethod
def test_migrations():
schema = {0: OldInitialSchema, # sickbeard.mainDB.InitialSchema,
31: sickbeard.mainDB.AddAnimeTVShow,
32: sickbeard.mainDB.AddAbsoluteNumbering,
@ -62,18 +63,33 @@ class OldInitialSchema(db.SchemaUpgrade):
if not self.hasTable('tv_shows') and not self.hasTable('db_version'):
queries = [
'CREATE TABLE db_version (db_version INTEGER);',
'CREATE TABLE history (action NUMERIC, date NUMERIC, showid NUMERIC, season NUMERIC, episode NUMERIC, quality NUMERIC, resource TEXT, provider TEXT)',
'CREATE TABLE imdb_info (indexer_id INTEGER PRIMARY KEY, imdb_id TEXT, title TEXT, year NUMERIC, akas TEXT, runtimes NUMERIC, genres TEXT, countries TEXT, country_codes TEXT, certificates TEXT, rating TEXT, votes INTEGER, last_update NUMERIC)',
'CREATE TABLE info (last_backlog NUMERIC, last_indexer NUMERIC, last_proper_search NUMERIC)',
'CREATE TABLE scene_numbering(indexer TEXT, indexer_id INTEGER, season INTEGER, episode INTEGER,scene_season INTEGER, scene_episode INTEGER, PRIMARY KEY(indexer_id, season, episode))',
'CREATE TABLE tv_shows (show_id INTEGER PRIMARY KEY, indexer_id NUMERIC, indexer NUMERIC, show_name TEXT, location TEXT, network TEXT, genre TEXT, classification TEXT, runtime NUMERIC, quality NUMERIC, airs TEXT, status TEXT, flatten_folders NUMERIC, paused NUMERIC, startyear NUMERIC, air_by_date NUMERIC, lang TEXT, subtitles NUMERIC, notify_list TEXT, imdb_id TEXT, last_update_indexer NUMERIC, dvdorder NUMERIC, archive_firstmatch NUMERIC, rls_require_words TEXT, rls_ignore_words TEXT, sports NUMERIC);',
'CREATE TABLE tv_episodes (episode_id INTEGER PRIMARY KEY, showid NUMERIC, indexerid NUMERIC, indexer NUMERIC, name TEXT, season NUMERIC, episode NUMERIC, description TEXT, airdate NUMERIC, hasnfo NUMERIC, hastbn NUMERIC, status NUMERIC, location TEXT, file_size NUMERIC, release_name TEXT, subtitles TEXT, subtitles_searchcount NUMERIC, subtitles_lastsearch TIMESTAMP, is_proper NUMERIC, scene_season NUMERIC, scene_episode NUMERIC);',
'CREATE UNIQUE INDEX idx_indexer_id ON tv_shows (indexer_id)',
'CREATE TABLE history ('
'action NUMERIC, date NUMERIC, showid NUMERIC, season NUMERIC, episode NUMERIC,'
' quality NUMERIC, resource TEXT, provider TEXT);',
'CREATE TABLE imdb_info (indexer_id INTEGER PRIMARY KEY, imdb_id TEXT, title TEXT,'
' year NUMERIC, akas TEXT, runtimes NUMERIC, genres TEXT, countries TEXT, country_codes TEXT,'
' certificates TEXT, rating TEXT, votes INTEGER, last_update NUMERIC);',
'CREATE TABLE info (last_backlog NUMERIC, last_indexer NUMERIC, last_proper_search NUMERIC);',
'CREATE TABLE scene_numbering(indexer TEXT, indexer_id INTEGER,'
' season INTEGER, episode INTEGER,scene_season INTEGER, scene_episode INTEGER,'
' PRIMARY KEY(indexer_id, season, episode));',
'CREATE TABLE tv_shows (show_id INTEGER PRIMARY KEY, indexer_id NUMERIC, indexer NUMERIC,'
' show_name TEXT, location TEXT, network TEXT, genre TEXT, classification TEXT, runtime NUMERIC,'
' quality NUMERIC, airs TEXT, status TEXT, flatten_folders NUMERIC, paused NUMERIC,'
' startyear NUMERIC, air_by_date NUMERIC, lang TEXT, subtitles NUMERIC, notify_list TEXT,'
' imdb_id TEXT, last_update_indexer NUMERIC, dvdorder NUMERIC, archive_firstmatch NUMERIC,'
' rls_require_words TEXT, rls_ignore_words TEXT, sports NUMERIC);',
'CREATE TABLE tv_episodes (episode_id INTEGER PRIMARY KEY, showid NUMERIC,'
' indexerid NUMERIC, indexer NUMERIC, name TEXT, season NUMERIC, episode NUMERIC,'
' description TEXT, airdate NUMERIC, hasnfo NUMERIC, hastbn NUMERIC, status NUMERIC,'
' location TEXT, file_size NUMERIC, release_name TEXT, subtitles TEXT, subtitles_searchcount NUMERIC,'
' subtitles_lastsearch TIMESTAMP, is_proper NUMERIC, scene_season NUMERIC, scene_episode NUMERIC);',
'CREATE UNIQUE INDEX idx_indexer_id ON tv_shows (indexer_id);',
'CREATE INDEX idx_showid ON tv_episodes (showid);',
'CREATE INDEX idx_sta_epi_air ON tv_episodes (status,episode, airdate);',
'CREATE INDEX idx_sta_epi_sta_air ON tv_episodes (season,episode, status, airdate);',
'CREATE INDEX idx_status ON tv_episodes (status,season,episode,airdate);',
'CREATE INDEX idx_tv_episodes_showid_airdate ON tv_episodes(showid,airdate)',
'CREATE INDEX idx_tv_episodes_showid_airdate ON tv_episodes(showid,airdate);',
'INSERT INTO db_version (db_version) VALUES (31);'
]
for query in queries:
@ -83,20 +99,24 @@ class OldInitialSchema(db.SchemaUpgrade):
cur_db_version = self.checkDBVersion()
if cur_db_version < MIN_DB_VERSION:
logger.log_error_and_exit(u'Your database version ('
+ str(cur_db_version)
+ ') is too old to migrate from what this version of SickGear supports ('
+ str(MIN_DB_VERSION) + ').' + '\n'
+ 'Upgrade using a previous version (tag) build 496 to build 501 of SickGear first or remove database file to begin fresh.'
)
logger.log_error_and_exit(
u'Your database version ('
+ str(cur_db_version)
+ ') is too old to migrate from what this version of SickGear supports ('
+ str(MIN_DB_VERSION) + ').' + '\n'
+ 'Upgrade using a previous version (tag) build 496 to build 501 of SickGear first or'
' remove database file to begin fresh.'
)
if cur_db_version > MAX_DB_VERSION:
logger.log_error_and_exit(u'Your database version ('
+ str(cur_db_version)
+ ') has been incremented past what this version of SickGear supports ('
+ str(MAX_DB_VERSION) + ').' + '\n'
+ 'If you have used other forks of SickGear, your database may be unusable due to their modifications.'
)
logger.log_error_and_exit(
u'Your database version ('
+ str(cur_db_version)
+ ') has been incremented past what this version of SickGear supports ('
+ str(MAX_DB_VERSION) + ').' + '\n'
+ 'If you have used other forks of SickGear,'
' your database may be unusable due to their modifications.'
)
return self.checkDBVersion()
@ -104,7 +124,7 @@ class OldInitialSchema(db.SchemaUpgrade):
class AddDefaultEpStatusToTvShows(db.SchemaUpgrade):
def execute(self):
self.addColumn('tv_shows', 'default_ep_status', 'TEXT', '')
self.setDBVersion(41)
self.setDBVersion(41, check_db_version=False)
if '__main__' == __name__:

Loading…
Cancel
Save