Repository: pymedusa/Medusa

Issue:
[APP SUBMITTED]: OperationalError: cannot rollback - no transaction is active
### INFO
**Python Version**: `2.7.9 (default, Sep 17 2016, 20:26:04) [GCC 4.9.2]`
**Operating System**: `Linux-4.9.35-v7+-armv7l-with-debian-8.0`
**Locale**: `UTF-8`
**Branch**: [develop](../tree/develop)
**Database**: `44.8`
**Commit**: pymedusa/Medusa@42b1e5f92de75f692099a53e0f61856c15e9e206
**Link to Log**: https://gist.github.com/a4e74c8ec6c4d6b883dae4aa56c88214
### ERROR
<pre>
2017-10-28 14:56:23 ERROR    SEARCHQUEUE-FORCED-71712 :: [BITHDTV] :: [42b1e5f] Unknown exception while searching BITHDTV. Error: 'cannot rollback - no transaction is active'
Traceback (most recent call last):
  File "/home/pi/Medusa/<a href="../blob/42b1e5f92de75f692099a53e0f61856c15e9e206/medusa/search/core.py#L555">medusa/search/core.py</a>", line 555, in search_providers
    down_cur_quality, manual_search, manual_search_type)
  File "/home/pi/Medusa/<a href="../blob/42b1e5f92de75f692099a53e0f61856c15e9e206/medusa/providers/generic_provider.py#L428">medusa/providers/generic_provider.py</a>", line 428, in find_search_results
    db.mass_action(cl)
  File "/home/pi/Medusa/<a href="../blob/42b1e5f92de75f692099a53e0f61856c15e9e206/medusa/db.py#L223">medusa/db.py</a>", line 223, in mass_action
    self.connection.rollback()
OperationalError: cannot rollback - no transaction is active
</pre>
---
_STAFF NOTIFIED_: @pymedusa/support @pymedusa/moderators


Discussion:

### INFO
**Python Version**: `2.7.14 (default, Dec 14 2017, 15:51:29) [GCC 6.4.0]`
**Operating System**: `Linux-4.14.13-unRAID-x86_64-with`
**Locale**: `None`
**Branch**: [master](../tree/master)
**Database**: `44.9`
**Commit**: pymedusa/Medusa@1a8dc66c7ec9231be0d3444710e476437c9ae1c8
**Link to Log**: https://gist.github.com/51e597575fb447f492789d4aea327c80
### ERROR
<pre>
2018-05-20 04:01:04 ERROR    SHOWQUEUE-REFRESH :: [1a8dc66] 281630: Error while refreshing show Scorpion. Error: cannot rollback - no transaction is active
Traceback (most recent call last):
  File "/app/medusa/medusa/show_queue.py", line 637, in run
    self.show.refresh_dir()
  File "/app/medusa/medusa/tv/series.py", line 1754, in refresh_dir
    self.load_episodes_from_dir()
  File "/app/medusa/medusa/tv/series.py", line 932, in load_episodes_from_dir
    cur_episode = self.make_ep_from_file(os.path.join(self.location, media_file))
  File "/app/medusa/medusa/tv/series.py", line 1393, in make_ep_from_file
    main_db_con.mass_action(sql_l)
  File "/app/medusa/medusa/db.py", line 229, in mass_action
    self.connection.rollback()
OperationalError: cannot rollback - no transaction is active
</pre>
---
_STAFF NOTIFIED_: @pymedusa/support @pymedusa/moderators


Resolving patch:
diff --git a/medusa/db.py b/medusa/db.py
--- a/medusa/db.py
+++ b/medusa/db.py
@@ -224,8 +224,7 @@ def mass_action(self, querylist=None, logTransaction=False, fetchall=False):
                     break
                 except sqlite3.OperationalError as e:
                     sql_results = []
-                    if self.connection:
-                        self.connection.rollback()
+                    self._try_rollback()
                     if "unable to open database file" in e.args[0] or "database is locked" in e.args[0]:
                         logger.log(u"DB error: " + ex(e), logger.WARNING)
                         attempt += 1
@@ -235,8 +234,7 @@ def mass_action(self, querylist=None, logTransaction=False, fetchall=False):
                         raise
                 except sqlite3.DatabaseError as e:
                     sql_results = []
-                    if self.connection:
-                        self.connection.rollback()
+                    self._try_rollback()
                     logger.log(u"Fatal error executing query: " + ex(e), logger.ERROR)
                     raise
 
@@ -244,6 +242,18 @@ def mass_action(self, querylist=None, logTransaction=False, fetchall=False):
 
             return sql_results
 
+    def _try_rollback(self):
+        if not self.connection:
+            return
+        try:
+            self.connection.rollback()
+        except sqlite3.OperationalError as error:
+            # See https://github.com/pymedusa/Medusa/issues/3190
+            if 'no transaction is active' in error.args[0]:
+                logger.log("Rollback not needed, skipping", logger.DEBUG)
+            else:
+                logger.log("Failed to perform rollback: {error!r}".format(error=error), logger.ERROR)
+
     def action(self, query, args=None, fetchall=False, fetchone=False):
         """
         Execute single query
@@ -333,10 +343,11 @@ def upsert(self, tableName, valueDict, keyDict):
 
         changesBefore = self.connection.total_changes
 
-        genParams = lambda myDict: [x + " = ?" for x in myDict]
+        def gen_params(my_dict):
+            return [x + " = ?" for x in my_dict]
 
-        query = "UPDATE [" + tableName + "] SET " + ", ".join(genParams(valueDict)) + " WHERE " + " AND ".join(
-            genParams(keyDict))
+        query = "UPDATE [" + tableName + "] SET " + ", ".join(gen_params(valueDict)) + " WHERE " + " AND ".join(
+            gen_params(keyDict))
 
         self.action(query, list(itervalues(valueDict)) + list(itervalues(keyDict)))
 


Test patch: