# Buggy code
def _upgrade_22_to_23(self):
    """
    Migrates the database to the new version.
    """
    self.status_update_func("Upgrading database from v%s to v%s..." % (22, 23))

    self.db.execute("""
DROP TABLE IF EXISTS BarterCast;
DROP INDEX IF EXISTS bartercast_idx;

DROP INDEX IF EXISTS Torrent_swift_torrent_hash_idx;
""")

    try:
        next(
            self.db.execute(
                "SELECT * From sqlite_master WHERE name == '_tmp_Torrent' and type == 'table';"
            )
        )

    except StopIteration:
        # no _tmp_Torrent table, check if the current Torrent table is new
        lines = [
            (0, "torrent_id", "integer", 1, None, 1),
            (1, "infohash", "text", 1, None, 0),
            (2, "name", "text", 0, None, 0),
            (3, "torrent_file_name", "text", 0, None, 0),
            (4, "length", "integer", 0, None, 0),
            (5, "creation_date", "integer", 0, None, 0),
            (6, "num_files", "integer", 0, None, 0),
            (7, "thumbnail", "integer", 0, None, 0),
            (8, "insert_time", "numeric", 0, None, 0),
            (9, "secret", "integer", 0, None, 0),
            (10, "relevance", "numeric", 0, "0", 0),
            (11, "source_id", "integer", 0, None, 0),
            (12, "category_id", "integer", 0, None, 0),
            (13, "status_id", "integer", 0, "0", 0),
            (14, "num_seeders", "integer", 0, None, 0),
            (15, "num_leechers", "integer", 0, None, 0),
            (16, "comment", "text", 0, None, 0),
            (17, "dispersy_id", "integer", 0, None, 0),
            (18, "last_tracker_check", "integer", 0, "0", 0),
            (19, "tracker_check_retries", "integer", 0, "0", 0),
            (20, "next_tracker_check", "integer", 0, "0", 0),
        ]
        i = 0
        is_new = True
        for line in self.db.execute("PRAGMA table_info(Torrent);"):
            if line != lines[i]:
                is_new = False
                break
            i += 1

        if not is_new:
            # create the temporary table
            self.db.execute("""
CREATE TABLE IF NOT EXISTS _tmp_Torrent (
  torrent_id       integer PRIMARY KEY AUTOINCREMENT NOT NULL,
  infohash		   text NOT NULL,
  name             text,
  torrent_file_name text,
  length           integer,
  creation_date    integer,
  num_files        integer,
  thumbnail        integer,
  insert_time      numeric,
  secret           integer,
  relevance        numeric DEFAULT 0,
  source_id        integer,
  category_id      integer,
  status_id        integer DEFAULT 0,
  num_seeders      integer,
  num_leechers     integer,
  comment          text,
  dispersy_id      integer,
  last_tracker_check    integer DEFAULT 0,
  tracker_check_retries integer DEFAULT 0,
  next_tracker_check    integer DEFAULT 0
);
""")

            # migrate Torrent table
            keys = (
                "torrent_id",
                "infohash",
                "name",
                "torrent_file_name",
                "length",
                "creation_date",
                "num_files",
                "thumbnail",
                "insert_time",
                "secret",
                "relevance",
                "source_id",
                "category_id",
                "status_id",
                "num_seeders",
                "num_leechers",
                "comment",
                "dispersy_id",
                "last_tracker_check",
                "tracker_check_retries",
                "next_tracker_check",
            )

            keys_str = ", ".join(keys)
            values_str = "?," * len(keys)
            insert_stmt = "INSERT INTO _tmp_Torrent(%s) VALUES(%s)" % (
                keys_str,
                values_str[:-1],
            )
            current_count = 0

            results = self.db.execute("SELECT %s FROM Torrent;" % keys_str)
            new_torrents = []
            for torrent in results:
                torrent_id, infohash, name, torrent_file_name = torrent[:4]

                filepath = os.path.join(
                    self.torrent_collecting_dir, hexlify(str2bin(infohash)) + ".torrent"
                )

                # Check if we have the actual .torrent
                torrent_file_name = None
                if os.path.exists(filepath):
                    torrent_file_name = filepath
                    tdef = TorrentDef.load(filepath)
                    # Use the name on the .torrent file instead of the one stored in the database.
                    name = tdef.get_name_as_unicode() or name

                new_torrents.append(
                    (torrent_id, infohash, name, torrent_file_name) + torrent[4:]
                )

                current_count += 1
                self.status_update_func(
                    "Upgrading database, %s records upgraded..." % current_count
                )

            self.status_update_func(
                "All torrent entries processed, inserting in database..."
            )
            self.db.executemany(insert_stmt, new_torrents)
            self.status_update_func("All updated torrent entries inserted.")

            self.db.execute("""
DROP TABLE IF EXISTS Torrent;
ALTER TABLE _tmp_Torrent RENAME TO Torrent;
""")

    # cleanup metadata tables
    self.db.execute("""
DROP TABLE IF EXISTS MetadataMessage;
DROP TABLE IF EXISTS MetadataData;

CREATE TABLE IF NOT EXISTS MetadataMessage (
  message_id             INTEGER PRIMARY KEY AUTOINCREMENT,
  dispersy_id            INTEGER NOT NULL,
  this_global_time       INTEGER NOT NULL,
  this_mid               TEXT NOT NULL,
  infohash               TEXT NOT NULL,
  previous_mid           TEXT,
  previous_global_time   INTEGER
);

CREATE TABLE IF NOT EXISTS MetadataData (
  message_id  INTEGER,
  data_key    TEXT NOT NULL,
  data_value  INTEGER,
  FOREIGN KEY (message_id) REFERENCES MetadataMessage(message_id) ON DELETE CASCADE
);
""")

    # cleanup all SearchCommunity and MetadataCommunity data in dispersy database
    self._purge_old_search_metadata_communities()

    # update database version
    self.db.write_version(23)


# Traceback (SQLError)
root@bbq:~/tribler# nosetests Tribler/Test/Core/Upgrade/test_db_upgrader.py -v -x
If no C{methodName} argument is passed to the constructor, L{run} will ... ok
test_reimport_torrents ... ERROR
ERROR

======================================================================
ERROR: test_reimport_torrents
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/defer.py", line 150, in maybeDeferred
result = f(*args, **kw)
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/utils.py", line 201, in runWithWarningsSuppressed
reraise(exc_info[1], exc_info[2])
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/utils.py", line 197, in runWithWarningsSuppressed
result = f(*a, **kw)
File "/root/tribler/Tribler/Test/test_as_server.py", line 56, in check
result = fun(*argv, **kwargs)
File "/root/tribler/Tribler/Test/Core/Upgrade/test_db_upgrader.py", line 55, in test_reimport_torrents
db_migrator.start_migrate()
File "/root/tribler/Tribler/Core/Upgrade/db_upgrader.py", line 59, in start_migrate
self._upgrade_22_to_23()
File "/root/tribler/Tribler/Core/Upgrade/db_upgrader.py", line 310, in _upgrade_22_to_23
""")
File "/root/tribler/Tribler/pyipv8/ipv8/util.py", line 49, in helper
return blockingCallFromThread(reactor, func, *args, **kargs)
File "/root/tribler/Tribler/pyipv8/ipv8/util.py", line 61, in blockingCallFromThread
return f(*args, **kwargs)
File "/root/tribler/Tribler/Core/CacheDB/sqlitecachedb.py", line 295, in execute
raise msg
SQLError: SQLError: error in view SuperPeer: no such table: main.__Peer_tmp
-------------------- >> begin captured logging << --------------------
Tribler.Core.Utilities.network_utils: DEBUG: Got a working random port 25506
TriblerConfig: DEBUG: Get random port 25506 for [libtorrent~port]
Tribler.Core.Utilities.network_utils: DEBUG: Got a working random port 6688
TriblerConfig: DEBUG: Get random port 6688 for [dispersy~port]
Tribler.Core.Utilities.network_utils: DEBUG: Got a working random port 27429
TriblerConfig: DEBUG: Get random port 27429 for [mainline_dht~port]
Tribler.Core.Utilities.network_utils: DEBUG: Got a working random port 50148
TriblerConfig: DEBUG: Get random port 50148 for [video_server~port]
Tribler.Core.Utilities.network_utils: DEBUG: Got a working random port 14895
TriblerConfig: DEBUG: Get random port 14895 for [libtorrent~anon_listen_port]
Tribler.Core.Utilities.network_utils: DEBUG: Got a working random port 25372
TriblerConfig: DEBUG: Get random port 25372 for [tunnel_community~socks5_listen_ports~0]
Tribler.Core.Utilities.network_utils: DEBUG: Got a working random port 8203
TriblerConfig: DEBUG: Get random port 8203 for [tunnel_community~socks5_listen_ports~1]
Tribler.Core.Utilities.network_utils: DEBUG: Got a working random port 44513
TriblerConfig: DEBUG: Get random port 44513 for [tunnel_community~socks5_listen_ports~2]
Tribler.Core.Utilities.network_utils: DEBUG: Got a working random port 37178
TriblerConfig: DEBUG: Get random port 37178 for [tunnel_community~socks5_listen_ports~3]
Tribler.Core.Utilities.network_utils: DEBUG: Got a working random port 51695
TriblerConfig: DEBUG: Get random port 51695 for [tunnel_community~socks5_listen_ports~4]
SQLiteCacheDB: INFO: begin page_size upgrade...
SQLiteCacheDB: INFO: ...end page_size upgrade
SQLiteCacheDB: INFO: Reading database version...
SQLiteCacheDB: INFO: Current database version is 17
SQLiteCacheDB: INFO: Beginning the first transaction...
SQLiteCacheDB: INFO: Start committing...
SQLiteCacheDB: INFO: Beginning another transaction...
SQLiteCacheDB: INFO: Start committing...
SQLiteCacheDB: INFO: Beginning another transaction...
SQLiteCacheDB: ERROR: cachedb: ===MainThread===
SQL Type: <type 'unicode'>
-----

DROP TABLE IF EXISTS Torrent;
ALTER TABLE _tmp_Torrent RENAME TO Torrent;

-----
None
======
Traceback (most recent call last):
File "/root/tribler/Tribler/Core/CacheDB/sqlitecachedb.py", line 282, in execute
return cur.execute(sql)
File "src/cursor.c", line 236, in resetcursor
SQLError: SQLError: error in view SuperPeer: no such table: main.__Peer_tmp
--------------------- >> end captured logging << ---------------------

# Fixed code
def _upgrade_22_to_23(self):
    """
    Migrates the database to the new version.
    """
    self.status_update_func("Upgrading database from v%s to v%s..." % (22, 23))

    self.db.execute("""
DROP TABLE IF EXISTS BarterCast;
DROP INDEX IF EXISTS bartercast_idx;

DROP INDEX IF EXISTS Torrent_swift_torrent_hash_idx;
""")

    try:
        next(
            self.db.execute(
                "SELECT * From sqlite_master WHERE name == '_tmp_Torrent' and type == 'table';"
            )
        )

    except StopIteration:
        # no _tmp_Torrent table, check if the current Torrent table is new
        lines = [
            (0, "torrent_id", "integer", 1, None, 1),
            (1, "infohash", "text", 1, None, 0),
            (2, "name", "text", 0, None, 0),
            (3, "torrent_file_name", "text", 0, None, 0),
            (4, "length", "integer", 0, None, 0),
            (5, "creation_date", "integer", 0, None, 0),
            (6, "num_files", "integer", 0, None, 0),
            (7, "thumbnail", "integer", 0, None, 0),
            (8, "insert_time", "numeric", 0, None, 0),
            (9, "secret", "integer", 0, None, 0),
            (10, "relevance", "numeric", 0, "0", 0),
            (11, "source_id", "integer", 0, None, 0),
            (12, "category_id", "integer", 0, None, 0),
            (13, "status_id", "integer", 0, "0", 0),
            (14, "num_seeders", "integer", 0, None, 0),
            (15, "num_leechers", "integer", 0, None, 0),
            (16, "comment", "text", 0, None, 0),
            (17, "dispersy_id", "integer", 0, None, 0),
            (18, "last_tracker_check", "integer", 0, "0", 0),
            (19, "tracker_check_retries", "integer", 0, "0", 0),
            (20, "next_tracker_check", "integer", 0, "0", 0),
        ]
        i = 0
        is_new = True
        for line in self.db.execute("PRAGMA table_info(Torrent);"):
            if line != lines[i]:
                is_new = False
                break
            i += 1

        if not is_new:
            # create the temporary table
            self.db.execute("""
CREATE TABLE IF NOT EXISTS _tmp_Torrent (
  torrent_id       integer PRIMARY KEY AUTOINCREMENT NOT NULL,
  infohash		   text NOT NULL,
  name             text,
  torrent_file_name text,
  length           integer,
  creation_date    integer,
  num_files        integer,
  thumbnail        integer,
  insert_time      numeric,
  secret           integer,
  relevance        numeric DEFAULT 0,
  source_id        integer,
  category_id      integer,
  status_id        integer DEFAULT 0,
  num_seeders      integer,
  num_leechers     integer,
  comment          text,
  dispersy_id      integer,
  last_tracker_check    integer DEFAULT 0,
  tracker_check_retries integer DEFAULT 0,
  next_tracker_check    integer DEFAULT 0
);
""")

            # migrate Torrent table
            keys = (
                "torrent_id",
                "infohash",
                "name",
                "torrent_file_name",
                "length",
                "creation_date",
                "num_files",
                "thumbnail",
                "insert_time",
                "secret",
                "relevance",
                "source_id",
                "category_id",
                "status_id",
                "num_seeders",
                "num_leechers",
                "comment",
                "dispersy_id",
                "last_tracker_check",
                "tracker_check_retries",
                "next_tracker_check",
            )

            keys_str = ", ".join(keys)
            values_str = "?," * len(keys)
            insert_stmt = "INSERT INTO _tmp_Torrent(%s) VALUES(%s)" % (
                keys_str,
                values_str[:-1],
            )
            current_count = 0

            results = self.db.execute("SELECT %s FROM Torrent;" % keys_str)
            new_torrents = []
            for torrent in results:
                torrent_id, infohash, name, torrent_file_name = torrent[:4]

                filepath = os.path.join(
                    self.torrent_collecting_dir, hexlify(str2bin(infohash)) + ".torrent"
                )

                # Check if we have the actual .torrent
                torrent_file_name = None
                if os.path.exists(filepath):
                    torrent_file_name = filepath
                    tdef = TorrentDef.load(filepath)
                    # Use the name on the .torrent file instead of the one stored in the database.
                    name = tdef.get_name_as_unicode() or name

                new_torrents.append(
                    (torrent_id, infohash, name, torrent_file_name) + torrent[4:]
                )

                current_count += 1
                self.status_update_func(
                    "Upgrading database, %s records upgraded..." % current_count
                )

            self.status_update_func(
                "All torrent entries processed, inserting in database..."
            )
            self.db.executemany(insert_stmt, new_torrents)
            self.status_update_func("All updated torrent entries inserted.")

            self.db.execute("""
DROP VIEW IF EXISTS CollectedTorrent;
DROP TABLE IF EXISTS Torrent;
ALTER TABLE _tmp_Torrent RENAME TO Torrent;
CREATE VIEW CollectedTorrent AS SELECT * FROM Torrent WHERE torrent_file_name IS NOT NULL;
""")

    # cleanup metadata tables
    self.db.execute("""
DROP TABLE IF EXISTS MetadataMessage;
DROP TABLE IF EXISTS MetadataData;

CREATE TABLE IF NOT EXISTS MetadataMessage (
  message_id             INTEGER PRIMARY KEY AUTOINCREMENT,
  dispersy_id            INTEGER NOT NULL,
  this_global_time       INTEGER NOT NULL,
  this_mid               TEXT NOT NULL,
  infohash               TEXT NOT NULL,
  previous_mid           TEXT,
  previous_global_time   INTEGER
);

CREATE TABLE IF NOT EXISTS MetadataData (
  message_id  INTEGER,
  data_key    TEXT NOT NULL,
  data_value  INTEGER,
  FOREIGN KEY (message_id) REFERENCES MetadataMessage(message_id) ON DELETE CASCADE
);
""")

    # cleanup all SearchCommunity and MetadataCommunity data in dispersy database
    self._purge_old_search_metadata_communities()

    # update database version
    self.db.write_version(23)