Depuis 2023, je travaille sur la conversion de code SQL d’Oracle, MySQL et SQL Server vers PostgreSQL. Le problème est sérieux. Voici quelques exemples concrets :

Le T-fighter ou jointure externe:

-- Oracle
SELECT *
  FROM a, b
 WHERE b.a_id (+) = a.id;

-- PostgreSQL
SELECT *
  FROM a
  LEFT OUTER JOIN b
    ON b.a_id = a.id;

START WITH et les jointures récursives:

-- Oracle
SELECT * FROM a
 START WITH a.id = 1
       CONNECT BY a.parent = PRIOR a.id;

-- PostgreSQL
WITH RECURSIVE recursive_a(id) AS (
    SELECT id
      FROM a
     WHERE id = 1

     UNION

    SELECT a.id
      FROM a
      JOIN recursive_a ON a.parent = recursive_a.id
)
SELECT * FROM recursive_a;

Celle-là est violente !

État des lieux

En 2023, la solution de référence était le moteur d’expressions rationnelles d’ora2pg. Malgré sa maturité, ce moteur présente de nombreuses faiblesses: très fragile par principe sur un langage aussi souple que SQL, aucun test de non-régression, des inversions de sens dans la requête finale, suppression systématique de commentaires de code, performance limitée, difficile à réutiliser en CLI ou API, etc.

C’était l’explosion de l’IA. Que faire ? Faut-il encore concevoir des structures de données et des algorithmes ? Ou plutôt attendre que les IA résolvent tous les problèmes ?

Une solution est peu explorée: la transpilation. C’est une technique très courante dans le monde javascript: TypeScript est un langage transpilé. Nous avons d’abord étudié cette piste.

tree-sitter, GritQL, etc.

Il y a énormément de parser SQL dans la nature: tree-sitter pour les éditeurs, sqlparser-rs et ses dérivés mais essentiellement: des forks du parser de requêtes de PostgreSQL.

tree-sitter est très incomplet sur SQL, son but n’est pas de comprendre les syntaxes. SQL est un gros défi pour le format JSON de définition des grammaires dans tree-sitter.

GritQL est très intéressant fonctionnellement, mais basé sur tree-sitter et dépend de JS. De plus, Grit ne permet pas d’enrichir le moteur avec le modèle de donnée pour connaître les types des colonnes, des opérateurs, etc. Cela le rend plus fragile.

[sqlglot] a le même problème: il ne sait traduire que des syntaxes simples, et encore. Par exemple, sqlglot convertit SELECT SYSDATE FROM DUAL en SELECT CURRENT_TIMESTAMP FROM DUAL. La clause FROM DUAL n’est pas supprimée. Pire, l’opérateur joinmark est tout simplement supprimé sans autre conversion!

Ensuite, vous avez une très longue liste de parser de requêtes SQL, pour beaucoup basés sur le parser de PostgreSQL. À l’exception notable de sqlparser-rs. Ces bibliothèques sont orientées interprétation de requêtes. Toutes perdent les commentaires, la casse et tous le style du code. Par exemple, CAST(a AS real) devient a::float4, le code est bien valide, mais la syntaxe original est perdue. Perdre les commentaires est inacceptable sur du code historique, parfois simplement pour des questions juridiques. Toutes ces bibliothèques sont totalement à côté pour le code procédural. Bref, il faut se retrousser les manches.

Parser manuel ou généré

Au début, écrire un parser est impressionnant, surtout pour le langage SQL. J’ai donc étudié des générateurs de parser: ANTLR4, lark, etc. Ces solutions se cassent souvent les dents sur le SQL, surtout multi-dialectes. Les fichiers de grammaires sont d’obscurs monolithes. Le code généré est très lourd.

Réutiliser un parser n’économise pas de concevoir l’AST, c’est-à-dire la structure de donnée manipulée par la logique de conversion. À Dalibo, j’ai choisi de me lancer dans ce projet ambitieux: un transpilateur SQL universel, basé sur un parser impératif manuel.

Mais le plus intéressant est d’avoir un parser impératif pour contrôler finement l’algorithme. Je reviendrais dans d’autres articles sur l’AST, le parser et les règles de transpilation. Pour faire un rapide bilan, voici un tableau comparatif des solutions:

Critère Générateur Manuel
Modèle Déclaratif Impératif
Lignes de code 300k 11k
Multi-dialecte non oui
Tests unitaires à faire inclus
Temps de compilation très long instantané
Nombres de fichiers <10 ~80
Taille de fichier >10k lignes entre 100 et 300 lignes

Pourquoi pas l’IA ?

Certes, les IA sont bien plus performantes en 2026. Néanmoins, l’IA n’est pas une solution sans contre-partie.

L’IA a un coût. L’agent a tendance à faire beaucoup d’essais-erreurs et l’on capitalise peu sur ces échecs, avouons-le. Un schéma SQL contient beaucoup d’expressions: valeurs par défaut, colonnes virtuelles, contraintes CHECK, index fonctionnels, data type complexes, vues, code procédural; sans compter les requêtes applicatives. Plus une application a de code SQL embarqué, plus le projet de migration sera long: audit avant migration effective, multiples itérations, sans compter les rebasages du projet suite aux nouveaux développements. Autant d’occasions d’exécuter le moteur de conversion. Le budget token va exploser !

L’IA a son entropie: tendance à plaire (phénomène du sycophante), hallucination, essais-erreurs et fausses pistes. Une IA a besoin d’informations fiables, déterministes et de qualité. Le contexte pour faire une bonne conversion est très large: quelle version d’Oracle ? Quels types de données ? Selon le RAG disponible, le taux d’hallucination d’un modèle descend au mieux à 3 à 5 %. Sur du code historique avec rarement des tests de non régression, le taux d’hallucination monte jusqu’à 30%. C’est un risque excessif pour du code métier en base de données. HexaCluster, spécialiste de la conversion de code SQL avec LLM, utilise également sur des algorithmes déterministes pour compenser les hallucinations.

Agent thinking

En réalité, la question n’est pas avec ou sans IA mais quelle place pour l’IA ? On peut présenter l’utilisation de l’IA sur un spectre. D’un côté la méthode traditionnelle sans IA, de l’autre tout balancer à l’IA et attendre. Entre les deux, on peut utiliser l’IA pour programmer, on peut aussi donner un outil de validation à l’IA pour la guider. C’est plutôt là que se positionne transqlate.

Un choix varié de solutions

Le logiciel libre propose aujourd’hui deux solutions pour convertir du code: le moteur d’expression rationnel d’ora2pg ou le transpilateur déterministe transqlate. Bien que propriétaire, nous allons le comparer à une IA pour le principe:

Critère ora2pg PostgreSQL for VSCode transqlate
Licence GPL souvent propriétaire PostgreSQL
Gouvernance individuelle corporation Entreprise
Technique regexp Inférence Édition d’AST
Syntaxes complexes oui oui oui
Fiabilité Faible Modérée Forte
Vitesse Modérée Lente rapide
Privé/hors-ligne oui non oui
Fichier plat non oui oui
SQL dans l’application non oui non
API non non Go
Intégration IDE non VS Code manuelle
Destination tout PostgreSQL Azure SQL tout PostgreSQL

Il est pertinent d’utiliser l’IA pour implémenter un transpiler. Déléguer toute la logique à l’IA est plus coûteux pour un résultat moins sûr. Le choix final dépendra du projet, de la dette technique, du budget et des compétences disponibles.

D’autres enjeux de la migration demeurent : la stratégie de conversion et le transfert performant des données. Le transpilateur intégrable dans le logiciel de migration ouvre de nombreuses pistes pour migrer efficacement. 2026 est une belle période pour envisager la migration vers PostgreSQL grâce au foisonnement de solutions.