Ë
    âß²j>T  ã                   ó   — d Z ddlZddlZddlZddlmZ ddlmZ ddlm	Z	 ddl
mZmZmZmZmZ ddlmZ  ej$                  d«      Zd	Zd
Zdefd„Zdefd„Zdej2                  defd„ZdZdej8                  dee   dee   fd„Z G d„ d«      Z y)zãFTS5 index setup for SessionDB: the CJK-bigram (cjk_unicode61) index DDL and
tokenizer loader, per-table schema ensure with tokenizer-capability fallback,
FTS-scoped corruption detection and the atomic fail-open trigger detach.é    N)ÚPath)ÚSequence)Úget_hermes_home)ÚFTS_CJK_STALE_KEYÚFTS_STALE_KEYÚ_FTS_CJK_TRIGGERSÚ_FTS_TRIGGERSÚrouted_sessions_setting©Úis_fts_scoped_corruption_errorÚhermes_statea\  
CREATE VIEW IF NOT EXISTS messages_fts_cjk_src AS
    SELECT id, role, content, tool_name, tool_calls
    FROM messages
    WHERE role <> 'tool';

CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts_cjk USING fts5(
    content,
    tool_name,
    tool_calls,
    content='messages_fts_cjk_src',
    content_rowid='id',
    tokenize='cjk_unicode61'
);
a	  
CREATE TRIGGER IF NOT EXISTS messages_fts_cjk_insert AFTER INSERT ON messages
WHEN new.role <> 'tool'
   AND (new.id > COALESCE((SELECT CAST(value AS INTEGER) FROM state_meta
                           WHERE key = 'fts_cjk_rebuild_high_water'), -1)
     OR new.id <= COALESCE((SELECT CAST(value AS INTEGER) FROM state_meta
                            WHERE key = 'fts_cjk_rebuild_progress'), -1))
BEGIN
    INSERT INTO messages_fts_cjk(rowid, content, tool_name, tool_calls)
    VALUES (new.id, new.content, new.tool_name, new.tool_calls);
END;

CREATE TRIGGER IF NOT EXISTS messages_fts_cjk_delete AFTER DELETE ON messages
WHEN old.role <> 'tool'
   AND (old.id > COALESCE((SELECT CAST(value AS INTEGER) FROM state_meta
                           WHERE key = 'fts_cjk_rebuild_high_water'), -1)
     OR old.id <= COALESCE((SELECT CAST(value AS INTEGER) FROM state_meta
                            WHERE key = 'fts_cjk_rebuild_progress'), -1))
BEGIN
    INSERT INTO messages_fts_cjk(messages_fts_cjk, rowid, content, tool_name, tool_calls)
    VALUES ('delete', old.id, old.content, old.tool_name, old.tool_calls);
END;

CREATE TRIGGER IF NOT EXISTS messages_fts_cjk_update
AFTER UPDATE OF content, tool_name, tool_calls, role ON messages
WHEN (old.content IS NOT new.content
    OR old.tool_name IS NOT new.tool_name
    OR old.tool_calls IS NOT new.tool_calls
    OR old.role IS NOT new.role)
   AND (old.id > COALESCE((SELECT CAST(value AS INTEGER) FROM state_meta
                           WHERE key = 'fts_cjk_rebuild_high_water'), -1)
     OR old.id <= COALESCE((SELECT CAST(value AS INTEGER) FROM state_meta
                            WHERE key = 'fts_cjk_rebuild_progress'), -1))
BEGIN
    INSERT INTO messages_fts_cjk(messages_fts_cjk, rowid, content, tool_name, tool_calls)
    SELECT 'delete', old.id, old.content, old.tool_name, old.tool_calls
    WHERE old.role <> 'tool';
    INSERT INTO messages_fts_cjk(rowid, content, tool_name, tool_calls)
    SELECT new.id, new.content, new.tool_name, new.tool_calls
    WHERE new.role <> 'tool';
END;
Úreturnc                  ó‚   — t        j                  d«      } | rt        | «      j                  «       S t	        «       dz  dz  S )z1Location of the cjk_unicode61 loadable extension.ÚHERMES_FTS5_CJK_SOÚlibzlibfts5_cjk.so)ÚosÚgetenvr   Ú
expanduserr   )Úenvs    ú5/home/ubuntu/.hermes/hermes-agent/hermes_state_fts.pyÚfts5_cjk_so_pathr   c   s9   € ä
�)‰)Ð(Ó
)€CÙ%(Œ4�‹9×ÑÓ!ÐZ¬oÓ.?À%Ñ.GÐJZÑ.ZÐZó    c                  óx   — t        dd«      } | du xs) t        | «      j                  «       j                  «       dvS )zKconfig.yaml ``sessions.cjk_fts`` (default on) for the profile being served.Úcjk_ftsÚHERMES_CJK_FTSN)Ú0ÚfalseÚoffÚno)r
   ÚstrÚstripÚlower)Úvalues    r   Ú_cjk_fts_config_enabledr$   i   s:   € ä# IÐ/?Ó@€EØ�Dˆ=ÒYœC ›J×,Ñ,Ó.×4Ñ4Ó6Ð>YÐYÐYr   Úconnc                 óD  — t        «       }t        «       r|j                  «       sy	 | j                  d«       	 | j	                  t        |«      «       | j                  d«       y# | j                  d«       w xY w# t        $ r t        j                  d|d¬«       Y yw xY w)zšBest-effort load of the cjk_unicode61 tokenizer; False (never raises) when
    the .so is absent, ``sessions.cjk_fts`` is off, or loading is compiled out.FTz#fts5_cjk extension load failed (%s)©Úexc_info)	r   r$   ÚexistsÚenable_load_extensionÚload_extensionr    Ú	ExceptionÚloggerÚwarning)r%   Úpaths     r   Úload_fts5_cjk_extensionr0   o   sŽ   € ô Ó€DÜ"Ô$¨D¯K©K¬MØð	Ø×"Ñ" 4Ô(ð	.Ø×Ñ¤ D£	Ô*à×&Ñ& uÔ-Øøð ×&Ñ& uÕ-ûäò Ü�‰Ð<¸dÈTˆÔRÙðús(   §A; ¹A% ÁA; Á%A8Á8A; Á;!BÂB)ÚcontentÚdataÚdocsizeÚidxÚconfigÚcursorÚfamiliesc                 óä  — g }|D ]Þ  }| j                  d|f«      j                  «       }|rŒ't        D �cg c]	  }|› d|› �‘Œ }}| j                  ddj                  d„ |D «       «      › d�|«      j	                  «       D �cg c]  }|d   ‘Œ	 }}|sŒŒ|D ]  }	| j                  d|	› d	�«       Œ t
        j                  d
|dj                  |«      «       |j                  |«       Œà |S c c}w c c}w )a—  Drop, per family, shadow tables whose virtual table row is absent from sqlite_master.

    Matches exact shadow names only (never a prefix LIKE, so the base family cannot reach
    ``messages_fts_trigram_*``) and leaves a family alone whenever its vtable is live. The
    shadows are derived index state; the caller recreates and rebuilds from ``messages``.
    Returns the families that were repaired.
    zbSELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ? AND sql LIKE 'CREATE VIRTUAL TABLE%'Ú_zASELECT name FROM sqlite_master WHERE type = 'table' AND name IN (ú,c              3   ó    K  — | ]  }d –— Œ y­w©ú?N© ©Ú.0r9   s     r   ú	<genexpr>z1_drop_orphan_fts_shadow_tables.<locals>.<genexpr>›   s   è ø€ ÒXnÐabÔY\ÑXnùó   ‚ú)r   zDROP TABLE "ú"zRDropped orphan FTS5 shadow tables of %s (%s); the index is recreated from messagesz, )ÚexecuteÚfetchoneÚ_FTS5_SHADOW_SUFFIXESÚjoinÚfetchallr-   r.   Úappend)
r6   r7   ÚrepairedÚfamilyÚvtable_liveÚsuffixÚshadowsÚrowÚorphansÚnames
             r   Ú_drop_orphan_fts_shadow_tablesrS   ˆ   s  € ð €HØò  ˆØ—n‘nð3àˆIó
÷ ‰(‹*ð	 	ñ
 ØÜ6KÖL¨F�f�X˜Q˜v˜hÒ'ÐLˆÐLØ%+§^¡^ØOÐPS×PXÑPXÑXnÐfmÔXnÓPnÐOoÐopÐqØó&
÷ ‰(‹*ö˜c�3�q“6ð ˆð ñ ØØò 	3ˆDØ�N‰N˜\¨$¨¨qÐ1Õ2ð	3ä�‰Ø`Ø�D—I‘I˜gÓ&ô	
ð 	�‰˜Õð+ ð, €Oùò Mùòs   ´C(Â C-c                   ó  — e Zd ZdZedej                  defd„«       Zedej                  defd„«       Z	edej                  defd„«       Zedej                  defd„«       Zedej                  defd	„«       Zdej                  dd
fd„Zdej                  dd
fd„Zdd„Zedej                  dd
fd„«       Zdej                  dededefd„Zedej*                  defd„«       Zdej*                  defd„ZdZdZdZdZdefd„ZdZy
)ÚSessionFtsSetupMixinzOFTS table/trigger lifecycle shared by schema init, optimize and the write path.Úexcr   c                 óv   — t        | «      j                  «       }d|v xr d|v xs t        j                  | «      S )zONo FTS5 module, or an optional tokenizer missing (same capability-error shape).zno such moduleÚfts5)r    r"   rU   Ú_is_trigram_unavailable_error©rV   Úerrs     r   Ú_is_fts5_unavailable_errorz/SessionFtsSetupMixin._is_fts5_unavailable_error­   s:   € ô �#‹h�n‰nÓˆØ  CÐ'Ò9¨F°c¨MÒuÔ>R×>pÑ>pÐqtÓ>uÐur   c                 óH   — t        | «      j                  «       }d|v xs d|v S )zŸOnly an optional tokenizer is missing (trigram needs SQLite >= 3.34;
        cjk_unicode61 is loadable): "this one index can't be served", never "disable FTS".zno such tokenizer: trigramz no such tokenizer: cjk_unicode61)r    r"   rZ   s     r   rY   z2SessionFtsSetupMixin._is_trigram_unavailable_error³   s+   € ô �#‹h�n‰nÓˆØ+¨sÐ2Ò_Ð6XÐ\_Ð6_Ð_r   r6   c                 ób   — | j                  d«      j                  «       }|duxr d|d   xs dvS )u•  messages_fts exists in ANY pre-v23 shape: every legacy shape lacks
        tool_name, so "stored CREATE lacks tool_name" catches them all. False when absent.

        v23's messages_fts is external-content over THREE real columns (content, tool_name, tool_calls).
        Every pre-v23 shape lacks the tool_name/tool_calls columns â€” whether the old inline single-column
        form (v11..v22) or the even older external-content single-column form (v10-era, pre-#16751). We
        therefore detect "needs optimize" as "the stored CREATE lacks the tool_name column", which is the
        precise v23 marker and correctly catches BOTH legacy variants.
        zLSELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'messages_fts'NÚ	tool_namer   Ú )rE   rF   ©r6   rP   s     r   Ú_db_has_legacy_inline_ftsz.SessionFtsSetupMixin._db_has_legacy_inline_ftsº   s=   € ð �n‰nØZó
ç
‰(‹*ð 	ð ˜$ˆÒD ;°s¸1±v²|ÀÐ#DÐDr   c                 ó~   — | j                  d«      j                  «       }|duxr d|d   xs dj                  «       v S )z[True when the trigram vtable still includes the tool_calls payload (FTS_STORAGE_VERSION 1).zTSELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'messages_fts_trigram'NÚ
tool_callsr   r`   )rE   rF   r"   ra   s     r   Ú%_db_has_trigram_tool_calls_projectionz:SessionFtsSetupMixin._db_has_trigram_tool_calls_projectionÊ   sF   € ð �n‰nØbó
ç
‰(‹*ð 	ð ˜$ˆÒI <°C¸±F²L¸b×3GÑ3GÓ3IÐ#IÐIr   c                 óJ   — | j                  |«      xs | j                  |«      S )z`True when the current FTS storage layout should be treated as stale (optimize-storage has work).)rb   re   )Úclsr6   s     r   Ú_db_needs_fts_storage_upgradez2SessionFtsSetupMixin._db_needs_fts_storage_upgradeÒ   s&   € ð ×,Ñ,¨VÓ4Òi¸×8aÑ8aÐbhÓ8iÐir   Nc                 óŽ   — t        | dd«      ryd| _        t        j                  d| j                  t
        j                  |«       y)zHLog once that the trigram tokenizer is missing; base FTS5 stays enabled.Ú_trigram_unavailable_warnedFNTzˆSQLite trigram tokenizer unavailable for %s (requires SQLite >= 3.34, this build is %s); CJK/substring search will fall back to LIKE: %s)Úgetattrrj   r-   ÚinfoÚdb_pathÚsqlite3Úsqlite_version©ÚselfrV   s     r   Ú_warn_trigram_unavailablez.SessionFtsSetupMixin._warn_trigram_unavailable×   s@   € ä�4Ð6¸Ô>ØØ+/ˆÔ(Ü�‰ð>ð �L‰LÜ×"Ñ"Øõ	
r   c                 ó|   — d| _         | j                  ry d| _        t        j                  d| j                  |«       y )NFTzµSQLite FTS5 unavailable for %s; full-text session search disabled. Run `hermes update` to rebuild the venv with a current Python (managed uv guarantees FTS5). (underlying error: %s))Ú_fts_enabledÚ_fts_unavailable_warnedr-   r.   rm   rp   s     r   Ú_warn_fts5_unavailablez+SessionFtsSetupMixin._warn_fts5_unavailableå   s<   € Ø!ˆÔØ×'Ò'ØØ'+ˆÔ$Ü�‰ðRð �L‰LØõ	
r   c                 óÆ  — 	 t        |j                  d«      j                  «       «      }| j                  s®|r¤|j                  ddj	                  d„ t
        D «       «      › d�t
        «      j                  «       D �cg c]  }|d   ‘Œ	 }}|rPt        j                  dt        «       «       |j                  dt        f«       |D ]  }|j                  d	|› �«       Œ d
| _        y	 	 |j                  t        «       |s‰|j                  dt        f«       |j                  d«      j                  «       d   dkD  rM|j                  d«      j                  «       d   }dt!        |«      fdfD ]  \  }}|j                  d||f«       Œ |j                  dt        f«      j                  «       rd
| _        y|j                  t"        «       |j                  d«      j                  «       }	|	 | _        yc c}w # t        j                  $ r! t        j                  dd¬«       d
| _        Y yw xY w# t        j                  $ r! t        j                  dd¬«       d
| _        Y yw xY w)u   Create / repair / self-heal the CJK-bigram index (see the module comment).
        Sets ``_fts_cjk_available``; never raises. Loaded + absent â†’ create (a
        populated DB gets backfill markers and is NOT served until optimize-storage
        backfills); loaded + present â†’ ensure triggers, honour the stale breadcrumb;
        NOT loaded + live triggers â†’ drop them (INSERTs must not fail at trigger time).zNSELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'messages_fts_cjk'zCSELECT name FROM sqlite_master WHERE type = 'trigger' AND name IN (r:   c              3   ó    K  — | ]  }d –— Œ y­wr<   r>   r?   s     r   rA   z>SessionFtsSetupMixin._ensure_fts_cjk_schema.<locals>.<genexpr>   ó   è ø€ Ò0P¸´Ñ0PùrB   rC   r   u
  messages_fts_cjk triggers present but the cjk_unicode61 tokenizer is unavailable (%s) â€” dropping the cjk triggers so message writes keep working. CJK search falls back to trigram/LIKE; run `hermes sessions optimize-storage` on a host with the extension to rebuild.z^INSERT INTO state_meta (key, value) VALUES (?, '1') ON CONFLICT(key) DO UPDATE SET value = '1'úDROP TRIGGER IF EXISTS FNzHmessages_fts_cjk presence check failed; CJK search stays on trigram/LIKETr'   z$DELETE FROM state_meta WHERE key = ?z2SELECT COUNT(*) FROM messages WHERE role <> 'tool'z)SELECT COALESCE(MAX(id), 0) FROM messagesÚfts_cjk_rebuild_high_water)Úfts_cjk_rebuild_progressr   zgINSERT INTO state_meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.valuez&SELECT 1 FROM state_meta WHERE key = ?zISELECT 1 FROM state_meta WHERE key = 'fts_cjk_rebuild_high_water' LIMIT 1z@messages_fts_cjk ensure failed; CJK search stays on trigram/LIKE)ÚboolrE   rF   Ú_fts_cjk_loadedrH   r   rI   r-   r.   r   r   Ú_fts_cjk_availablern   ÚOperationalErrorÚexecutescriptÚFTS_CJK_TABLE_SQLr    ÚFTS_CJK_TRIGGER_SQL)
rq   r6   Úcjk_presentÚrÚliveÚtrigÚhwÚkÚvÚbackfill_pendings
             r   Ú_ensure_fts_cjk_schemaz+SessionFtsSetupMixin._ensure_fts_cjk_schemaò   s‚  € ð%	Ü˜vŸ~™~Ø`ó ç‰h‹jóˆKð ×'Ò'ÙØ*0¯.©.ð(Ø(+¯©Ñ0PÔ>OÔ0PÓ(PÐ'QÐQRðTä)ó+÷ ‘h“jö	" Q˜A˜a›Dð "�Dð "ñ
 äŸ™ð=ô -Ó.ôð Ÿ™ðIä.Ð0ôð
 %)ò M˜DØ"ŸN™NÐ-DÀTÀFÐ+KÕLðMà*/�Ô'Øð5 (ðD	,Ø× Ñ Ô!2Ô3Ùà—‘ÐEÔHYÐG[Ô\ð —>‘>Ð"VÓW×`Ñ`ÓbÐcdÑeÐhiÒiØŸ™Ð(SÓT×]Ñ]Ó_Ð`aÑb�Bà5´s¸2³wÐ?ÐAbð!ò ™˜˜1ð Ÿ™ðTà ˜Fõðð �~‰~ÐFÔIZÐH\Ó]×fÑfÔhà*/�Ô'ØØ× Ñ Ô!4Ô5Ø%Ÿ~™~Ø[ó ç‰h‹jð ð +;Ð&:ˆDÕ#ùòs"øô2 ×'Ñ'ò 	Ü�N‰NðØ)-ð ô ð ',ˆDÔ#Ùð	ûôB ×'Ñ'ò 	,Ü�N‰NðØ)-ð ô ð ',ˆDÖ#ð	,ús>   ‚A:G5 Á<G0ÂAG5 Ã&CH, Æ3<H, Ç0G5 Ç51H)È(H)È,1I ÉI c                 óv   — t         D ]  }	 | j                  d|› �«       Œ y # t        j                  $ r Y Œ0w xY w)Nrz   )r	   rE   rn   r€   )r6   Útriggers     r   Ú_drop_fts_triggersz'SessionFtsSetupMixin._drop_fts_triggers?  sD   € ä$ò 	ˆGðØ—‘Ð!8¸¸	ÐBÕCñ	øô ×+Ñ+ò Ùðús   ‹"¢8·8Ú
table_nameÚddlc                 ó  — | j                  ||«      }|€y	 |j                  |«       y# t        j                  $ rP}| j	                  |«      s‚ | j                  |«      r| j                  |«       n| j                  |«       Y d }~yd }~ww xY w)NFT)Ú_fts_table_prober�   rn   r€   r\   rY   rr   rv   )rq   r6   r�   r‘   ÚstatusrV   s         r   Ú_ensure_fts_schemaz'SessionFtsSetupMixin._ensure_fts_schemaG  s†   € Ø×&Ñ& v¨zÓ:ˆØˆ>Øð	à× Ñ  Ô%ØøÜ×'Ñ'ò 	Ø×2Ñ2°3Ô7Øà×1Ñ1°#Ô6Ø×.Ñ.¨sÕ3à×+Ñ+¨CÔ0Üûð	ús   —) ©B¼ABÂBc                 ó   — t        | «      S )af  Corruption SQLite identifies as FTS-scoped (SQLITE_CORRUPT_VTAB, or an ``fts5:``
        report naming ``messages_fts*`` on builds without result codes); a bare malformed
        image is structural. One rule, shared with ``classify_persistence_error`` and the
        gateway transcript retry: see :func:`hermes_state_errors.is_fts_scoped_corruption_error`.r   )rV   s    r   Ú_is_fts_write_corruption_errorz3SessionFtsSetupMixin._is_fts_write_corruption_errorY  s   € ô .¨cÓ2Ð2r   c                 ó   — | j                   r| j                  |«      sy| j                  «        	 | j                  5  | j	                  «        | j
                  €| j                  d¬«       | j
                  j                  d«       	 | j
                  j                  dt        f«       | j
                  j                  ddj                  d	„ t        D «       «      › d
�t        «      j                  «       }|r!| j
                  j                  dt        f«       | j                  | j
                  j                  «       «       | j
                  j                  «        	 ddd«       d| _        d| _         d| _        d| _        t(        j+                  d|«       y# t         $ r | j
                  j#                  «        ‚ w xY w# 1 sw Y   ŒdxY w# t$        j&                  $ r }t(        j+                  d|«       Y d}~yd}~ww xY w)zîDetach corrupt FTS indexes so canonical writes can continue. Breadcrumb +
        trigger drop commit atomically: once triggers are absent the index has a
        gap of unknown extent, so nobody may reinstall them without a full rebuild.FNÚwrite)ÚcontextzBEGIN IMMEDIATEziINSERT INTO state_meta (key, value) VALUES (?, '1') ON CONFLICT(key) DO UPDATE SET value = excluded.valuez@SELECT 1 FROM sqlite_master WHERE type = 'trigger' AND name IN (r:   c              3   ó    K  — | ]  }d –— Œ y­wr<   r>   r?   s     r   rA   z<SessionFtsSetupMixin._enter_fts_fail_open.<locals>.<genexpr>v  ry   rB   z	) LIMIT 1zNCould not detach corrupt FTS indexes; canonical write still cannot proceed: %sTz­state.db FTS indexes remain corrupt (%s); disabled FTS sync and retrying the canonical write. Search temporarily uses LIKE until a later SessionDB open rebuilds the indexes.)rt   r—   Ú_raise_if_db_corruptÚ_lockÚ_raise_if_db_replacedÚ_connÚ_reopen_after_close_lockedrE   r   rH   r   rF   r   Ú_drop_all_fts_triggersr6   ÚcommitÚBaseExceptionÚrollbackrn   ÚErrorr-   ÚerrorÚ
_fts_staleÚ_trigram_availabler   )rq   rV   Úcjk_triggers_presentÚ
detach_excs       r   Ú_enter_fts_fail_openz)SessionFtsSetupMixin._enter_fts_fail_opena  sÑ  € ð × Ò ¨×(KÑ(KÈCÔ(PØØ×!Ñ!Ô#ð"	Ø—‘ñ Ø×*Ñ*Ô,Ø—:‘:Ð%Ø×3Ñ3¸GÐ3ÔDØ—
‘
×"Ñ"Ð#4Ô5ðØ—J‘J×&Ñ&ðPä&Ð(ôð
 ,0¯:©:×+=Ñ+=ð(Ø(+¯©Ñ0PÔ>OÔ0PÓ(PÐ'Qð R"ð"ô *ó	,÷
 ‘h“jð )ñ ,ØŸ
™
×*Ñ*ðTä.Ð0ôð
 ×/Ñ/°·
±
×0AÑ0AÓ0CÔDØ—J‘J×%Ñ%Õ'÷1ðD ˆŒØ!ˆÔØ"'ˆÔØ"'ˆÔÜ�‰ð;ð ô		
ð øô' %ò Ø—J‘J×'Ñ'Ô)Øðú÷3ð ûô8 �}‰}ò 	Ü�L‰LØ`Øôô ûð	úsB   °G
 ¼A
F>ÂCFÅG
 Æ%F;Æ;F>Æ>GÇG
 Ç
G=ÇG8Ç8G=iô  g      @gš™™™™™É?Úfts_v22_trash_c           	      ó�   — t        |j                  d| j                  j                  dd«      dz   f«      j	                  «       «      S )z‹True when demoted v22 shadow tables are still awaiting teardown.
        Caller must hold ``self._lock`` (or pass a migration-time cursor).zSSELECT 1 FROM sqlite_master WHERE type = 'table' AND name LIKE ? ESCAPE '\' LIMIT 1r9   z\_ú%)r}   rE   Ú_FTS_TRASH_PREFIXÚreplacerF   )rq   r%   s     r   Ú_has_fts_trashz#SessionFtsSetupMixin._has_fts_trash¦  sF   € ô �D—L‘LØbØ×#Ñ#×+Ñ+¨C°Ó7¸#Ñ=Ð?ó
÷ ‰(‹*óð 	r   )Úmessages_ftsÚmessages_fts_trigramÚmessages_fts_cjk)r   N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ústaticmethodrn   r€   r}   r\   rY   ÚCursorrb   re   Úclassmethodrh   rr   rv   rŒ   r�   r    r•   ÚDatabaseErrorr—   r«   Ú_FTS_REBUILD_CHUNK_ROWSÚ_FTS_REBUILD_DUTY_FACTORÚ_FTS_REBUILD_MIN_PAUSEr¯   r±   Ú_FTS_TABLESr>   r   r   rU   rU   ª   sÐ  „ ÙYàðv¨×(@Ñ(@ð vÀTò vó ðvð
 ð`¨7×+CÑ+Cð `Èò `ó ð`ð ðE¨'¯.©.ð E¸Tò Eó ðEð ðJ°g·n±nð JÈò Jó ðJð ðj°7·>±>ð jÀdò jó ðjð
¨W×-EÑ-Eð 
È$ó 
ð
¨'×*BÑ*Bð 
Àtó 
óK,ðZ ð 7§>¡>ð °dò ó ðð¨¯©ð ÀSð Èsð ÐW[ó ð$ ð3¨G×,AÑ,Að 3Àdò 3ó ð3ð4¨×(=Ñ(=ð 4À$ó 4ðx "ÐØ"ÐØ Ðð
 )Ðð dó ð O�Kr   rU   )!r¸   Úloggingr   rn   Úpathlibr   Útypingr   Úhermes_constantsr   Úhermes_state_commonr   r   r   r	   r
   Úhermes_state_errorsr   Ú	getLoggerr-   r‚   rƒ   r   r}   r$   Ú
Connectionr0   rG   rº   r    ÚlistrS   rU   r>   r   r   ú<module>rÊ      sÇ   ðñLó Û 	Û Ý Ý å ,÷õ å >ð 
ˆ×	Ñ	˜>Ó	*€ð,Ð ð )Ð ðX[˜$ó [ðZ ó Zð '×"4Ñ"4ð ¸ó ð, HÐ ð¨7¯>©>ð ÀXÈcÁ]ð ÐW[Ð\_ÑW`ó ÷DFOò FOr   