La base de données la plus utilisée au monde a mis 25 ans à vérifier ses types de données

La base de données la plus utilisée au monde a mis 25 ans à vérifier ses types de données

SQLiteBase de donnéesSécurité des TypesSTRICTIngénierie

Sources:HN + Evan Hahn blog + web research · HN

Le 27 novembre 2021, SQLite publiait sa version 3.37.0. Pas de doublement des performances, pas de fonctionnalité clinquante : juste la possibilité d’ajouter un mot à la fin d’une instruction CREATE TABLE : STRICT.

Qu’est-ce que cela signifie ? En langage clair : à partir de ce jour, SQLite a enfin appris à refuser une chose — « mettre un nom dans une colonne de numéro de téléphone ».

À ce moment-là, cela faisait déjà 21 ans qu’il existait. Et c’est la base de données invisible que chaque application de votre téléphone utilise.

Logo officiel de SQLite — ce moteur de base de données léger pilote plus de mille milliards de bases de données actives dans le monde. Source : sqlite.org

Les fondations invisibles de votre téléphone

D’abord, corrigeons un malentendu répandu : SQLite n’est pas un « logiciel » que vous pouvez télécharger sur l’App Store. Il n’y a pas d’icône « SQLite » sur votre téléphone. C’est un moteur de base de données — caché à l’intérieur des applications, stockant et gérant les données en silence.

Les conversations WeChat, les transactions Alipay, le cache vidéo de Douyin, le répertoire téléphonique, les mots de passe du navigateur, les cartes hors ligne… Derrière tout cela, il y a SQLite.

Selon des estimations fiables, plus de mille milliards de bases de données SQLite tournent simultanément dans le monde. Aucune autre base de données n’approche ce chiffre. C’est incontestablement la « numéro un mondial ».

Mais ce champion a une « spécialité » pour le moins surprenante : il ne vérifie absolument pas si les données que vous lui confiez sont du bon type.

« Âge : ‘Dupont’ ? Pas de problème, entrez. »

Qu’est-ce que « ne pas vérifier le type des données » ? Je vais utiliser une analogie concrète.

Vous allez à la banque pour ouvrir un compte. L’employé vous tend un formulaire. Il y a une case « âge » et une case « nom ». Vous écrivez « Dupont » dans la case âge, et « 42 » dans la case nom — normalement, l’employé vous rend le formulaire : « Monsieur, l’âge doit être un nombre, le nom doit être du texte. »

SQLite en mode par défaut, c’est comme si l’employé regardait votre formulaire et disait, d’un air impassible : « D’accord, vous mettez ce que vous voulez, j’encaisse. Âge : ‘Dupont’ ? Enregistré. Nom : ‘42’ ? Très bien. C’est votre liberté. »

Dans le code, cela donne : vous créez une table, vous déclarez que la colonne « âge » stocke des entiers (INTEGER) et la colonne « nom » du texte (TEXT). Puis vous exécutez :

INSERT INTO utilisateurs (âge) VALUES ('Je ne suis pas un nombre');

Dans MySQL, PostgreSQL et autres bases de données, cette instruction génère immédiatement une erreur. Dans SQLite ? Elle réussit. Aucun avertissement. Dans votre colonne « âge » trône désormais paisiblement une valeur texte « Je ne suis pas un nombre ».

Ce n’est pas un cas marginal. Le 11 juillet 2026, le développeur Evan Hahn publiait un article de blog « Préférez les tables STRICT dans SQLite », qui a recueilli près de 200 points et 89 commentaires sur Hacker News. Les commentaires regorgent de développeurs partageant leurs « gamelles » sur ce sujet.

Figure 1 : Comparaison du comportement entre mode STRICT et mode non-STRICT

Comparaison STRICT : à gauche, le mode par défaut (toutes les données sont acceptées) ; à droite, le mode STRICT (refus immédiat si le type ne correspond pas). Source : auteur, d'après le blog d'Evan Hahn et la documentation officielle SQLite.

OpérationNon-STRICT (défaut)Mode STRICT
Écrire 'abc' (texte) dans une colonne INTEGER✅ Accepté❌ Erreur
Écrire '123' (texte numérique, conversion sans perte) dans INTEGER✅ Accepté✅ Accepté
Déclarer un type GARBAGE (faute de frappe / type fictif) pour une colonne✅ Accepté❌ Erreur
Écrire n’importe quel type dans une colonne ANY✅ Accepté✅ Accepté
Créer une table sans déclarer le type d’une colonne✅ Accepté❌ Erreur
Types autorisésIllimitéINT, INTEGER, REAL, TEXT, BLOB, ANY

Une guerre philosophique qui a duré 20 ans

Ce n’est ni un oubli, ni de la paresse. C’est un choix de conception délibéré de D. Richard Hipp, le créateur de SQLite. Le site officiel de SQLite consacre une page entière, « Les avantages du typage flexible », à défendre cette absence de vérification des types.

Pour comprendre l’origine de ce choix, il faut revenir en l’an 2000. Hipp travaillait alors pour un sous-traitant de la marine de guerre américaine et avait besoin d’une base de données légère pour les systèmes embarqués sur des navires. Les solutions du marché étaient soit trop lourdes, soit nécessitaient un serveur — totalement irréaliste dans l’environnement d’un navire de guerre. Il a donc écrit la sienne.

Une source d’influence majeure : TCL — le langage de programmation que Hipp connaissait le mieux. TCL est un langage à typage dynamique : le programmeur n’a pas besoin de déclarer le type d’une variable à l’avance ; tout peut être traité comme une chaîne de caractères. Hipp a importé cette philosophie dans SQLite : vous déclarez le type d’une colonne ? Très bien, mais ce n’est qu’une suggestion. Ce que vous y mettez réellement, c’est vous qui décidez.

Pendant les 20 années qui ont suivi, un débat s’est poursuivi dans le monde des bases de données : le « typage flexible » est-il une fonctionnalité ou un bug ?

Les arguments du camp favorable (Hipp et son équipe) sont au nombre de trois :

Premièrement : « J’ai codé pendant 35 ans et je n’ai jamais vu un bug arrêté par la vérification de type. » Hipp écrit dans la documentation officielle qu’après des décennies de développement de TCL et SQLite, il ne se souvient d’aucune défaillance logicielle due à l’absence de contrainte de type. Sa conclusion : la vérification de type n’est utile que dans les langages de bas niveau proches du matériel comme le C et le C++ — dans un moteur SQL qui traite toutes les données comme des « objets-valeurs », elle n’apporte pas grand-chose.

Deuxièmement : « La vérification de type n’arrête que les erreurs grossières et évidentes. » L’argument est cinglant : mettre « nom » dans une case « âge » est une absurdité que la vérification peut effectivement bloquer — mais une absurdité trop évidente, qu’un test quelconque révélerait immédiatement. Ce qui vous fait passer trois jours à débugger, c’est d’avoir inversé le prénom et le nom — les deux sont du texte, la vérification de type ne voit rien. Hipp estime que la vérification de type donne au développeur un faux sentiment de sécurité que « les données sont propres ».

Troisièmement : « La flexibilité permet de faire ce qu’aucune autre base de données ne peut faire. » Par exemple, utiliser une seule table comme stockage clé-valeur pour des types de données quelconques, recycler une colonne abandonnée à d’autres usages, ou importer directement un fichier CSV malpropre exporté d’Excel pour le nettoyer plus tard.

Les arguments du camp opposé sont tout aussi solides :

« Ces erreurs ‘évidentes’ deviennent une aiguille introuvable dans une botte de foin de millions de lignes. La vérification de type n’a jamais été destinée à arrêter les bugs que vous attrapez en debug — elle est là pour prévenir le moment, à 3 h du matin en production, où il n’y a aucune erreur dans les logs mais où les données des utilisateurs commencent à devenir systématiquement incohérentes. »

« Tu dis que tu as codé 35 ans sans voir de bug de type ? SQLite lui-même est écrit en C, et tu profites de la vérification de type du C quand tu le compiles. Tu t’appuies sur un système de types strict pour garantir que SQLite lui-même ne contient pas d’erreurs, mais tu dis que la vérification de type n’est pas importante pour les autres ? »

Dans les commentaires de HN, une analogie a été citée à plusieurs reprises : « C’est comme utiliser UDP à la place de TCP — sacrifier la vérification des données pour la vitesse et la simplicité, puis réimplémenter manuellement la retransmission, le réordonnancement et la validation au niveau applicatif. Et au final, tu te rends compte que tu viens juste de réécrire un TCP de moins bonne qualité. »

Un autre commentateur est encore plus direct : « Ajuster les valeurs par défaut pour la performance, on peut l’accepter. Les ajuster pour la correction — ça laisse un goût amer. »

Ce que fait réellement le mode STRICT

Revenons à novembre 2021. Le mot-clé STRICT fait trois choses :

1. Refuser les écritures de type non conforme. Mettre du texte dans une colonne d’entiers ? Erreur. Mettre un nombre dans une colonne de texte ? Accepté — car le nombre peut être converti en texte sans perte. Mettre la chaîne '123' dans une colonne d’entiers ? Accepté aussi — car '123' peut être parfaitement converti en nombre 123. STRICT regarde si la « valeur peut être convertie sans perte », pas seulement le type apparent. C’est plus intelligent que de nombreuses bases de données à typage strict.

2. Refuser les types de données fictifs. En mode non-STRICT, quand vous écrivez GARBAGE, DATETIME, JSON, UUID ou BLOBB comme type de colonne — SQLite accepte tout, en le traitant silencieusement comme un type générique. En mode STRICT, seuls six types sont reconnus : INT, INTEGER, REAL, TEXT, BLOB, ANY. Si vous tapez BLOB en BLOBB par erreur ? Il vous le signale immédiatement.

3. Quand vous avez besoin de flexibilité, utilisez ANY. STRICT n’est pas un couperet. Si vous déclarez une colonne de type ANY, elle acceptera n’importe quelle donnée — comme en mode par défaut. La différence : les endroits flexibles sont ceux que vous désignez, pas tous les endroits par défaut.

Pourquoi avoir attendu 21 ans ?

De 2000 à 2021, 21 ans. Pourquoi un mécanisme de vérification aussi basique a-t-il traversé deux générations de développeurs avant d’arriver ?

La réponse se trouve dans la promesse fondamentale de SQLite : la rétrocompatibilité.

Les développeurs de SQLite suivent une règle quasi obsessionnelle : le code SQLite que vous écrivez aujourd’hui doit fonctionner à 100 % après une mise à jour de version dix ans plus tard. Cela signifie que le comportement par défaut ne peut jamais être modifié. Si on le changeait, les mille milliards d’instances SQLite en fonctionnement dans le monde pourraient rencontrer des problèmes.

Figure 2 : Chronologie de l’évolution de la sécurité des types dans SQLite

2000 ─ SQLite 1.0 publié, typage flexible comme philosophie centrale

      │   « Les types de colonnes sont des suggestions, pas des contraintes »

2009 ─ SQLite 3.6.19 : support syntaxique des clés étrangères
      │   Mais désactivé par défaut, nécessite PRAGMA foreign_keys = ON

      │   Pendant les 12 années suivantes, l'option STRICT est débattue
      │   Mais toujours rejetée par la règle de rétrocompatibilité

2021 ─ SQLite 3.37.0 : support des tables STRICT
      │   Ajout du mot-clé STRICT à la fin de CREATE TABLE, activable par table
      │   Pas de bascule globale — toujours la philosophie du « choisis »

2026 ─ Evan Hahn publie : « Préférez les tables STRICT dans SQLite »
      │   HN 199 points, 89 commentaires, le débat continue

Trois jalons sur 21 ans, chacun suivant le même principe : on peut ajouter des fonctionnalités, mais on ne peut pas changer le comportement par défaut.

Ce n’est pas un cas isolé. Les clés étrangères — qui empêchent de supprimer un utilisateur tout en laissant dix mille commandes « sans propriétaire » dans la table des commandes — SQLite supporte cette syntaxe depuis 2009, mais elle reste désactivée par défaut. À chaque connexion à la base de données, vous devez exécuter manuellement :

PRAGMA foreign_keys = ON;

pour activer la vérification des clés étrangères. Même raison : changer la valeur par défaut briserait la rétrocompatibilité.

Dans la discussion HN, quelqu’un a proposé un compromis : comme les navigateurs, permettre de déclarer COMPAT_MODE=2026 lors de la création de la base, et les nouvelles versions activent automatiquement la configuration recommandée de l’époque. Mais cette proposition n’a pas été retenue à ce jour.

Un commentateur a écrit cette phrase : « SQLite change très, très rarement les valeurs par défaut, parce que leur promesse de rétrocompatibilité est quasi sacrée. Ils ne veulent pas qu’un logiciel écrit pour SQLite 3.53 plante après une mise à jour vers 3.54 parce que CREATE TABLE est soudainement passé en mode STRICT. »

Cette phrase résume parfaitement le dilemme de SQLite : d’un côté, la pulsion évolutive de « toujours s’améliorer » ; de l’autre, le serment de « ne jamais rien changer ».

SQLite a réussi précisément parce qu’il ne contrôle rien

À ce stade, une question contre-intuitive se pose naturellement : si SQLite a autant de conceptions « par défaut non sécurisées », comment se fait-il qu’il soit la base de données la plus populaire au monde ?

La réponse se trouve dans sa philosophie. Le succès de SQLite vient en grande partie de son « laisser-faire ».

Pas d’installation, pas de serveur, pas de fichier de configuration. Une bibliothèque de quelques centaines de Ko s’intègre à une application et fonctionne. Pas de vérification de type de données — stockez ce que vous voulez. Pas de vérification des clés étrangères — vous assumez. Pas de niveau d’isolation des transactions — on exécute d’abord, on réfléchit après.

Cette approche minimaliste a une contrepartie : vous pouvez mettre SQLite dans un téléphone, un navigateur, un capteur IoT, un routeur, une télévision connectée, une voiture, un système de divertissement en avion — il ne fait jamais d’exigences, ne réclame jamais de ressources, et ne plante jamais au démarrage.

Comme une prise universelle — on peut y brancher n’importe quelle fiche. Et si ça fait un court-circuit, ce n’est pas de son ressort.

L’apparition du mode STRICT signifie que cette base de données qui n’a « rien contrôlé » pendant 21 ans a enfin admis une réalité : quand vos utilisateurs passent de quelques douzaines de programmeurs C professionnels à des millions de développeurs d’applications de niveaux variés dans le monde entier, la « liberté » par défaut devient un « risque » par défaut.

Épilogue

Cette histoire de SQLite, remise dans la perspective plus large du génie logiciel, est le reflet de la maturation progressive de toute une industrie.

Les logiciels des débuts s’adressaient à une poignée d’utilisateurs avertis. La philosophie était : « On vous donne un maximum de liberté ; si ça casse, c’est votre problème. » Aujourd’hui, les logiciels s’adressent à des milliards d’utilisateurs ordinaires, et la conception s’est déplacée de la « liberté » vers la « sécurité » et la « protection contre les erreurs ».

Le mode STRICT n’est pas une avancée technologique enthousiasmante — ce qu’il fait, MySQL et PostgreSQL le font depuis leur premier jour. Mais le fait qu’il ait mis 21 ans à arriver illustre silencieusement une vérité : beaucoup de ces « fonctionnalités de base » que nous tenons aujourd’hui pour acquises ont été acquises au prix de dix, vingt ans d’accumulation d’expérience, de débats, d’erreurs et de retours en arrière.

La prochaine fois que l’application de votre téléphone stocke tranquillement des données dans SQLite en arrière-plan, souvenez-vous : ce champion invisible qui travaille fidèlement dans votre téléphone depuis des milliers de jours n’a appris, au cours de sa 21e année d’existence, qu’une compétence qu’un enfant maîtrise à la maternelle —

ne pas mettre ses chaussures dans son assiette.


Références :