@@ -81,12 +81,15 @@ def __repr__(self):
8181MODE_TEXT = 3
8282MODE_PICKLE = 4
8383
84+ # settings starting with sqlite_ are used as PRAGMAs in sqlite
85+ # use with care
8486DEFAULT_SETTINGS = {
8587 u'statistics' : 0 , # False
8688 u'tag_index' : 0 , # False
8789 u'eviction_policy' : u'least-recently-stored' ,
8890 u'size_limit' : 2 ** 30 , # 1gb
8991 u'cull_limit' : 10 ,
92+ u'sqlite_query_only' : False ,
9093 u'sqlite_auto_vacuum' : 1 , # FULL
9194 u'sqlite_cache_size' : 2 ** 13 , # 8,192 pages
9295 u'sqlite_journal_mode' : u'wal' ,
@@ -484,6 +487,9 @@ def __init__(self, directory=None, timeout=60, disk=Disk, **settings):
484487 ' and could not be created' % self ._directory
485488 )
486489
490+ # this must be processed now because it is used in Cache._con
491+ self .open_in_query_only = settings .get ('sqlite_query_only' , False )
492+
487493 sql = self ._sql_retry
488494
489495 # Setup Settings table.
@@ -524,14 +530,16 @@ def __init__(self, directory=None, timeout=60, disk=Disk, **settings):
524530 # Set cached attributes: updates settings and sets pragmas.
525531
526532 for key , value in sets .items ():
527- query = 'INSERT OR REPLACE INTO Settings VALUES (?, ?)'
528- sql (query , (key , value ))
529- self .reset (key , value )
533+ if not self .sqlite_query_only :
534+ query = 'INSERT OR REPLACE INTO Settings VALUES (?, ?)'
535+ sql (query , (key , value ))
536+ self .reset (key , value , update = not self .sqlite_query_only )
530537
531538 for key , value in METADATA .items ():
532- query = 'INSERT OR IGNORE INTO Settings VALUES (?, ?)'
533- sql (query , (key , value ))
534- self .reset (key )
539+ if not self .sqlite_query_only :
540+ query = 'INSERT OR IGNORE INTO Settings VALUES (?, ?)'
541+ sql (query , (key , value ))
542+ self .reset (key , update = not self .sqlite_query_only )
535543
536544 (self ._page_size ,), = sql ('PRAGMA page_size' ).fetchall ()
537545
@@ -600,10 +608,11 @@ def __init__(self, directory=None, timeout=60, disk=Disk, **settings):
600608
601609 # Create tag index if requested.
602610
603- if self .tag_index : # pylint: disable=no-member
604- self .create_tag_index ()
605- else :
606- self .drop_tag_index ()
611+ if not self .sqlite_query_only :
612+ if self .tag_index : # pylint: disable=no-member
613+ self .create_tag_index ()
614+ else :
615+ self .drop_tag_index ()
607616
608617 # Close and re-open database connection with given timeout.
609618
@@ -666,6 +675,11 @@ def _con(self):
666675 if key .startswith ('sqlite_' ):
667676 self .reset (key , value , update = False )
668677
678+ # the settings read fro the DB never contain query_only
679+ # so we manually force it here, if it has been passed as a parameter
680+ if self .open_in_query_only :
681+ self .reset ('sqlite_query_only' , 1 , update = False )
682+
669683 return con
670684
671685
@@ -751,8 +765,9 @@ def _transact(self, retry=False, filename=None):
751765 begin = True
752766 self ._txn_id = tid
753767 break
754- except sqlite3 .OperationalError :
755- if retry :
768+ except sqlite3 .OperationalError as e :
769+ # TODO: this is potentially an infinite loop anyway
770+ if retry and 'readonly' not in str (e ):
756771 continue
757772 if filename is not None :
758773 _disk_remove (filename )
0 commit comments