sqlite-fts5-corruption-rebuild

Par divinevideo · divine-mobile

Corrige les erreurs SQLite « database disk image is malformed » causées par des index FTS5 corrompus. À utiliser quand : (1) UPDATE/INSERT échoue avec « stepping, database disk image is malformed » mais que `PRAGMA integrity_check` renvoie « ok », (2) Seuls certains enregistrements spécifiques échouent à la mise à jour alors que d'autres réussissent, (3) Les enregistrements contiennent du texte sale avec des tabulations, des sauts de ligne ou des caractères inhabituels qui ont été insérés dans des colonnes indexées par FTS5. Le message d'erreur trompeur suggère une corruption disque, mais le vrai problème est une corruption de l'index FTS5 due à un contenu textuel malformé.

npx skills add https://github.com/divinevideo/divine-mobile --skill sqlite-fts5-corruption-rebuild

Corruption d'Index SQLite FTS5 à partir de Données Erronées

Problème

SQLite retourne « database disk image is malformed » (code d'erreur 11) lors de la tentative d'UPDATE ou INSERT sur des enregistrements, même si PRAGMA integrity_check rapporte que la base de données est « ok ». L'erreur n'affecte que certains enregistrements, pas toutes les écritures.

Contexte / Conditions de Déclenchement

  • Message d'erreur : Error: stepping, database disk image is malformed (11)
  • PRAGMA integrity_check retourne ok (trompeur !)
  • Les requêtes SELECT sur les mêmes enregistrements fonctionnent correctement
  • Seuls certains enregistrements ne peuvent pas être mis à jour ; d'autres enregistrements de la même table se mettent à jour avec succès
  • Les enregistrements affectés contiennent du texte avec des tabulations incorporées (\t), des sauts de ligne (\n), ou d'autres caractères de contrôle dans des colonnes indexées par FTS5
  • Un processus concurrent (comme un serveur Node.js) peut avoir la base de données ouverte

Solution

  1. Identifier les tables FTS5 liées à la table affectée :

    SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '%fts%';
  2. Arrêter tous les processus maintenant la base de données ouverte (la reconstruction nécessite un accès exclusif) :

    kill $(lsof -ti :PORT)  # Tuer le processus serveur
  3. Reconstruire l'index FTS5 :

    INSERT INTO table_fts(table_fts) VALUES('rebuild');

    Remplacer table_fts par le nom réel de votre table FTS5 (par ex., people_fts).

  4. Réessayer l'opération échouée - elle devrait maintenant réussir.

  5. Redémarrer votre serveur d'application.

Vérification

  • La requête UPDATE/INSERT précédemment échouée réussit maintenant
  • Les requêtes de recherche en texte intégral retournent toujours les résultats corrects
  • Plus d'erreurs « malformed » lors des écritures ultérieures

Exemple

# L'erreur se produit :
sqlite3 data/tracker.db "UPDATE people SET name = 'More' WHERE id = 11;"
# Error: stepping, database disk image is malformed (11)

# Mais le contrôle d'intégrité réussit :
sqlite3 data/tracker.db "PRAGMA integrity_check;"
# ok

# Et SELECT fonctionne bien :
sqlite3 data/tracker.db "SELECT id, name FROM people WHERE id = 11;"
# 11|More Masajes\t\n\t\tEscort 23 años...

# Correction : Arrêter le serveur, reconstruire l'index FTS5
kill $(lsof -ti :3001)
sqlite3 data/tracker.db "INSERT INTO people_fts(people_fts) VALUES('rebuild');"

# Maintenant la mise à jour fonctionne :
sqlite3 data/tracker.db "UPDATE people SET name = 'More' WHERE id = 11;"
# Success!

Prévention

  • Nettoyer le texte avant insertion dans des colonnes indexées par FTS5 :
    const cleanName = rawName.replace(/[\t\n\r]+/g, ' ').trim();
  • Supprimer les caractères de contrôle des données scrappées avant insertion en base de données
  • Envisager l'utilisation de tables FTS5 content= (contenu externe) qui peuvent être reconstruites indépendamment sans affecter la table principale

Remarques

  • Le code d'erreur 11 (SQLITE_CORRUPT) est identique à une corruption réelle du disque, ce qui rend ce problème difficile à diagnostiquer
  • La corruption se trouve dans les tables fantômes FTS5 (_data, _idx, _docsize), pas dans la table principale, ce qui explique pourquoi integrity_check réussit
  • Si rebuild échoue avec « database is locked », assurez-vous qu'aucun autre processus n'a la base de données ouverte (vérifier avec lsof ou fuser)
  • Cela peut également survenir quand des enregistrements sont supprimés ou mis à jour de l'extérieur (par ex., via sqlite3 CLI) tandis qu'une connexion en mode WAL est active

Références

Skills similaires