
    ikF                         d Z ddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
mZ  ej                  d      Z ej                         Z G d d      Z G d dej                         Z G d	 d
e      Zy)a  Implementations to make access to SQLite databases a little more convenient.

:py:obj:`SQLiteAppl`
  Abstract class with which DB applications can be implemented.

:py:obj:`SQLiteProperties`:
  Class to manage properties stored in a database.

Examplarical implementations based on :py:obj:`SQLiteAppl`:

:py:obj:`searx.cache.ExpireCacheSQLite` :
  Cache that manages key/value pairs in a SQLite DB, in which the key/value
  pairs are deleted after an "expire" time.  This type of cache is used, for
  example, for the engines, see :py:obj:`searx.enginelib.EngineCache`.

:py:obj:`searx.favicons.cache.FaviconCacheSQLite` :
  Favicon cache that manages the favicon BLOBs in a SQLite DB.

----
    N)loggersqlitedbc                   v    e Zd ZdZedddej                  fd       Zd
dZe	dej                  fd       Z
d Zy	)	DBSessionzA *thead-local* DB sessionapp
SQLiteApplreturnc                     t        t        dd      i }|t        _        t        j                  j                  |j                        }| | |      }|j
                  S )zkReturns a thread local DB connection.  The connection is only
        established once per thread.
        DBSession_mapN)getattrTHREAD_LOCALr   getdb_urlconn)clsr   url_to_sessionsessions       /root/searxng/searx/sqlitedb.pyget_connectzDBSession.get_connect*   sR    
 <$7?35N)7L&$0$>$>$B$B3::$N?#hG||    c                     t        j                         | _         || _        d | _        t	        t
        dd       i }|t
        _        | t
        j                  | j                  j                  <   y )Nr   )uuiduuid4r   _connr   r   r   r   )selfr   r   s      r   __init__zDBSession.__init__8   sQ    #zz|	"04
<$7?35N)7L&6:""488??3r   c                 P   dt        j                         j                   d| j                  j                  j
                   d| j                  j                   d}| j                  5| j                  j                         | _        t        j                  d|       | j                  S )N[z] DBSession: ()z%s --> created new connection)	threadingcurrent_threadidentr   	__class____name__r   r   connectr   debugr   msgs     r   r   zDBSession.connB   s    )**,223=TXXEWEWE`E`Daabcgckckcrcrbsstu::))+DJLL8#> zzr   c                 r    	 | j                   | j                   j                          y y # t        $ r Y y w xY wN)r   close	Exception)r   s    r   __del__zDBSession.__del__M   s<    
	zz% 

  " &  		s   &* 	66N)r   r   )r%   
__module____qualname____doc__classmethodsqlite3
Connectionr   r   propertyr   r.    r   r   r   r   '   sV    $l w/A/A  ; g((  r   r   c                      e Zd ZU dZi Zeeef   ed<   dZe	ed<   	 dddde
j                     Zeed	<   	 d
Zeed<   	  eedk7        ddZeeee	z  ez  dz  f   ed<   	 defdZd Zde
j$                  fdZde
j$                  fdZde
j$                  fdZede
j$                  fd       Zde
j$                  defdZde
j$                  fdZy)r   zAbstract base class for implementing convenient DB access in SQLite
    applications.  In the constructor, a :py:obj:`SQLiteProperties` instance is
    already aggregated under ``self.properties``.DDL_CREATE_TABLES   	DB_SCHEMAzsingle-threadzmulti-thread
serialized)r   r9      SQLITE_THREADING_MODEWALSQLITE_JOURNAL_MODEr   )check_same_threadcached_statementsNSQLITE_CONNECT_ARGSr   c                 `    || _         t        |      | _        d| _        | j	                          y NF)r   SQLiteProperties
properties
_init_done_compatibilityr   r   s     r   r   zSQLiteAppl.__init__   s(    !,<V,D %r   c                 F   | j                   dk(  rd | _        nRd| j                    d}t        j                         dkD  rt	        j
                  |       nt	        j                  |       t        j                  dk  r%t	        j                  dt        j                         y y )Nr;   z SQLite library is compiled with zO mode, read https://docs.python.org/3/library/sqlite3.html#sqlite3.threadsafetyr9   )r<   #   zDSQLite runtime library version %s is not supported (require >= 3.35))r=   _DBr!   active_countr   errorwarningr3   sqlite_version_infocriticalsqlite_versionr(   s     r   rH   zSQLiteAppl._compatibility   s    %%526DH 343M3M2N O\ \  %%'!+S!s#&&'1OOVX_XnXn 2r   r	   c                     t        j                  | j                  fi | j                  }|j	                  d| j
                          | j                  |       |S )NzPRAGMA journal_mode=)r3   r4   r   rB   executer?   register_functionsr   r   s     r   _connectzSQLiteAppl._connect   sO    !!$++J1I1IJ+D,D,D+EFG%r   c           
         t         j                  dk  r| j                  j                  dd       dt	        j
                         j                   d| j                  j                   d| j                   d| j                   d| j                   
}t        j                  |       | j                         5 }| j                  |       ddd       |S # 1 sw Y   S xY w)	ac  Creates a new DB connection (:py:obj:`SQLITE_CONNECT_ARGS`).  If not
        already done, the DB schema is set up.  The caller must take care of
        closing the resource.  Alternatively, :py:obj:`SQLiteAppl.DB` can also
        be used (the resource behind `self.DB` is automatically closed when the
        process or thread is terminated).
        )r<      
autocommitNr   ] r   z) z // )sysversion_inforB   popr!   r"   r#   r$   r%   r   r?   r   r'   rW   init)r   r)   r   s      r   r&   zSQLiteAppl.connect   s     g%$$((t< 	((*001DNN4K4K3LAdkk] [(()d.F.F-GI 	 	S]]_ 	IIdO		s   4CCr   c                 0    |j                  ddd d       y)a  Create user-defined_ SQL functions.

        ``REGEXP(<pattern>, <field>)`` : 0 | 1
           `re.search`_ returns (int) 1 for a match and 0 for none match of
           ``<pattern>`` in ``<field>``.

           .. code:: sql

              SELECT '12' AS field WHERE REGEXP('^[0-9][0-9]$', field)
              -- 12

              SELECT REGEXP('[0-9][0-9]', 'X12Y')
              -- 1
              SELECT REGEXP('[0-9][0-9]', 'X1Y')
              -- 0

        .. _user-defined: https://docs.python.org/3/library/sqlite3.html#sqlite3.Connection.create_function
        .. _deterministic: https://sqlite.org/deterministic.html
        .. _re.search: https://docs.python.org/3/library/re.html#re.search
        regexp   c                 6    t        j                  | |      rdS dS )Nr9   r   )research)xys     r   <lambda>z/SQLiteAppl.register_functions.<locals>.<lambda>  s    BIIaOq QR r   T)deterministicN)create_functionrV   s     r   rU   zSQLiteAppl.register_functions   s    , 	Xq*Rbfgr   c                     | j                   dk(  rt        j                  |       }nt        j                  |       }| j                  |       |S )a
  Provides a DB connection.  The connection is a *singleton* and
        therefore well suited for read access.  If
        :py:obj:`SQLITE_THREADING_MODE` is ``serialized`` only one DB connection
        is created for all threads.

        .. note::

           For dedicated `transaction control`_, it is recommended to create a
           new connection (:py:obj:`SQLiteAppl.connect`).

        .. _transaction control:
            https://docs.python.org/3/library/sqlite3.html#sqlite3-controlling-transactions
        r;   )r=   r   r   r_   rV   s     r   DBzSQLiteAppl.DB  sF    $ %%5 ((.D((.D
 			$r   c                    | j                   ryd| _         t        j                  d| j                         | j                  j                  |       | j	                  d      }||5  | j                  |       ddd       yt        |      }|| j                  k7  r%t        j                  d| j                  d|      t        j                  d|       y# 1 sw Y   yxY w)	aQ  Initializes the DB schema and properties, is only executed once even
        if called several times.

        If the initialization has not yet taken place, it is carried out and a
        `True` is returned to the caller at the end.  If the initialization has
        already been carried out in the past, `False` is returned.
        FTzinit DB: %sr:   NzExpected DB schema vz, DB schema is vzDB_SCHEMA = %s)rG   r   r'   r   rF   r_   create_schemaintr:   r3   DatabaseError)r   r   vers      r   r_   zSQLiteAppl.init?  s     ??]DKK0T"ook*; )""4()  c(Cdnn$++Z^ZhZhjm,nooLL)3/) s   %CCc                    t        j                  d       | j                  j                  d| j                         | j                  j                  dd       |5  | j
                  j                         D ]6  \  }}|j                  |       | j                  j                  d| d|       8 	 d d d        y # 1 sw Y   y xY w)Nzcreate schema ..r:   LAST_MAINTENANCE zTable z created)r   r'   rF   setr:   r8   itemsrT   )r   r   
table_namesqls       r   rn   zSQLiteAppl.create_schema[  s    '(K8.3 	O#'#9#9#?#?#A O
CS!##fZL$A:NO	O 	O 	Os   AB88C)r%   r/   r0   r1   r8   dictstr__annotations__r:   ro   r3   threadsafetyr=   r?   boolrB   r   rH   r4   rW   r&   rU   r5   rl   r_   rn   r6   r   r   r   r   [   sD   5 )+tCH~*IsC
 " !--"/3 /	  %$ ""7<"GH	8c#c'$,t"334 :xs  (',, ++ *hw'9'9 h0 $G&& $ $L++  8O'"4"4 Or   r   c                      e Zd ZU dZdZeed<   dZeed<   	 dZeed<   dZ	eed	<   d
Z
eed<   dZeed<   dZeed<    eej                        Zeeeez  ez  dz  f   ed<   defdZdej(                  defdZd!dedej.                  dej.                  fdZdedeez  fdZdedefdZd!dedej.                  fdZd"dededefdZdej(                  fdZdefd Zy)#rE   aW  Simple class to manage properties of a DB application in the DB.  The
    object has its own DB connection and transaction area.

    .. code:: sql

       CREATE TABLE IF NOT EXISTS properties (
         name       TEXT,
         value      TEXT,
         m_time     INTEGER DEFAULT (strftime('%s', 'now')),
         PRIMARY KEY (name))

    r>   r?   zCREATE TABLE IF NOT EXISTS properties (
  name       TEXT,
  value      TEXT,
  m_time     INTEGER DEFAULT (strftime('%s', 'now')),  -- last modified (unix epoch) time in sec.
  PRIMARY KEY (name))DDL_PROPERTIESz+SELECT value FROM properties WHERE name = ?SQL_GETz,SELECT m_time FROM properties WHERE name = ?
SQL_M_TIMEzINSERT INTO properties (name, value) VALUES (?, ?)    ON CONFLICT(name) DO UPDATE   SET value=excluded.value, m_time=strftime('%s', 'now')SQL_SETz%DELETE FROM properties WHERE name = ?
SQL_DELETEzGSELECT name FROM sqlite_master WHERE type='table' AND name='properties'SQL_TABLE_EXISTSNrB   r   c                 @    || _         d| _        | j                          y rD   )r   rG   rH   rI   s     r   r   zSQLiteProperties.__init__  s    ! %r   r   r	   c                     | j                   ryd| _         t        j                  d| j                         |j	                  | j
                        }|j                         | j                  |       y)z2Initializes DB schema of the properties in the DB.FTzinit properties of DB: %s)rG   r   r'   r   rT   r   fetchonern   )r   r   ress      r   r_   zSQLiteProperties.init  sY     ??0$++>ll4001<<>!t$r   namedefaultc                 ~    | j                   j                  | j                  |f      j                         }||S |d   S )z_Returns the value of the property ``name`` or ``default`` if property
        not exists in DB.r   )rl   rT   r   r   )r   r   r   r   s       r   __call__zSQLiteProperties.__call__  s:     ggoodllTG4==?;N1vr   valuec                     | j                   5  | j                   j                  | j                  ||f       ddd       y# 1 sw Y   yxY w)zuSet ``value`` of property ``name`` in DB.  If property already
        exists, update the ``m_time`` (and the value).N)rl   rT   r   )r   r   r   s      r   ru   zSQLiteProperties.set  s:     WW 	9GGOODLL4-8	9 	9 	9s	   )?Ac                     | j                   5  | j                   j                  | j                  |f      }ddd       |j                  S # 1 sw Y   j                  S xY w)z$Delete of property ``name`` from DB.N)rl   rT   r   rowcount)r   r   curs      r   deletezSQLiteProperties.delete  sG    WW 	<''//$//D7;C	<||	<||s   (A		Ac                     | j                   j                  d|f      }|j                         }||S |j                  D cg c]  }|d   	 }}t	        t        ||            S c c}w )z\Returns the DB row of property ``name`` or ``default`` if property
        not exists in DB.z'SELECT * FROM properties WHERE name = ?r   )rl   rT   r   descriptionry   zip)r   r   r   r   rowcolumn	col_namess          r   r   zSQLiteProperties.row  sb     ggooG$Qlln;N-0__=6VAY=	=C	3'(( >s    A#c                     | j                   j                  | j                  |f      }|j                         }||S t	        |d         S )z(Last modification time of this property.r   )rl   rT   r   r   ro   )r   r   r   r   r   s        r   m_timezSQLiteProperties.m_time  s?    ggoodoow7lln;N3q6{r   c                 h    |5  |j                  | j                         d d d        y # 1 sw Y   y xY wr+   )rT   r   rV   s     r   rn   zSQLiteProperties.create_schema  s,     	.LL,,-	. 	. 	.s   (1c           	         g }| j                   j                  d      D ]Q  }|\  }}}t        j                  j                  |      j	                  d      }|j                  d| d|dd|        S dj                  |      S )Nz*SELECT name, value, m_time FROM propertiesz%Y-%m-%d %H:%M:%Sz[last modified: r[   20sz: 
)rl   rT   datetimefromtimestampstrftimeappendjoin)r   linesr   r   r   r   s         r   __str__zSQLiteProperties.__str__  s    77??#OP 	KC"%D%&&44V<EEFYZFLL+F82d3Zr%IJ	K yyr   r+   )r   )r%   r/   r0   r1   r?   rz   r{   r   r   r   r   r   r   ry   r   rB   ro   r}   r   r3   r4   r_   tAnyr   ru   r   r   r   rn   r   r6   r   r   rE   rE   f  s[     %$NC  :@GS@DJD	D S 
 >J=	4 c  ?C:CaCa>bc39t#3d#::;bs 
++ 
 
S 155 AEE 9 9C#I 93 3 
) 
)aee 
)3  S .'"4"4 .   r   rE   )r1   typingr   abcr   rd   r3   r\   r!   r   searxr   getChildlocalr   r   ABCr   rE   r6   r   r   <module>r      ss   *  
  	  
   		$y 1 1hHO HOVn z n r   