2011-07-12 6 views
2

Je développe et maintient une bibliothèque d'abstraction de base de données appelée jOOQ, qui vise à "internaliser" SQL en tant que DSL externe en Java. Le but de cette entreprise est de permettre la construction et l'exécution en toute sécurité de tous les éléments de syntaxe SQL possibles du SGBDR le plus populaire. Le DSL interne de jOOQ devient de plus en plus complexe, et j'aimerais l'avoir officiellement. L'idée est que je voudrais être en mesure d'avoir une sorte de définition formelle de SQL en entrée, par exemple. L'entrée peut également être définie en XML ou tout autre méta-langage descriptif.Outil pour "internalisation" d'un DSL externe en Java

select ::= subquery [ for-update-clause ] 
subquery ::= SELECT [ { ALL | DISTINCT | UNIQUE } ] select-list 
      [ FROM table-reference ] .. 
select-list ::= expression [ [ AS ] alias ] [, expression ... ] 
expression ::= ... 
alias ::= ... 
table-reference ::= ... 

Une fois que j'ai cette entrée, je voudrais générer à partir de cette entrée un ensemble d'interfaces Java, qui modélisent la syntaxe définie en Java. interfaces exemple serait:

// The first "step" of query creation is modelled with this interface 
interface Select0 { 

    // The various SELECT keywords are modelled with methods 
    // returning the subsequent generated syntax-element 
    Select1 select(Expression...); 
    Select1 selectAll(Expression...); 
    Select1 selectDistinct(Expression...); 
    Select1 selectUnique(Expression...); 
} 

// The second "step" of query creation is optional, hence it 
// inherits from the third "step" 
interface Select1 extends Select2 { 

    // Here a FROM clause may be added optionally 
    Select2 from(TableReference...); 
} 

// To keep it simple, the third "step" is the last for this example 
interface Select2 extends SelectEnd { 
    // WHERE, CONNECT BY, PIVOT, UNPIVOT, GROUP BY, HAVING, ORDER BY, etc... 
} 

Avec les interfaces ci-dessus, il sera possible de construire des requêtes SQL en Java, comme jOOQ permet déjà de faire aujourd'hui:

create.select(ONE, TWO).from(TABLE)... 
create.selectDistinct(ONE, TWO).from(TABLE)... 
// etc... 

Aussi, je voudrais excluez certains éléments de syntaxe pour certaines versions spécifiques. Par exemple. Lorsque je crée jOOQ pour une utilisation exclusive avec MySQL, il n'est pas nécessaire de prendre en charge l'instruction SQL MERGE.

Existe-t-il une bibliothèque existante implémentant une telle approche générale afin d'internaliser formellement et DSL externe à Java? Ou devrais-je rouler le mien?

+1

Je regarderais [ANTLR] (http://www.antlr.org/), il a plusieurs grammaires SQL, et [cette version de PLSQL] (http://www.antlr.org/grammar/1279318813752 /PLSQL.g) semble prometteur –

+0

@Sean, je ne suis pas sûr si j'ai bien compris ANTLR, mais c'est pour l'analyse et la vérification syntaxique des chaînes, non? Mais ce que je veux, c'est "l'internalisation DSL".La sortie devrait être un ensemble d'interfaces, qui donnent l'impression que SQL pourrait être écrit nativement en Java (ce que jOOQ fait déjà aujourd'hui). Je vais mettre à jour la question. –

+0

oui, mais vous pouvez utiliser la grammaire SQL pour créer des classes Java aussi –

Répondre

1

Ce que vous essayez vraiment de faire est de traduire le SQL générique en appels sur vos API internes. Cela semble raisonnable. Pour ce faire, vous avez besoin d'un analyseur syntaxique pour "SQL générique" et d'un moyen de générer du code à partir de cet analyseur syntaxique. Vous avez généralement besoin de l'analyseur syntaxique pour construire une arborescence de syntaxe abstraite, vous avez besoin d'une table de symboles (pour savoir quels sont les noms de tables, les noms de colonnes et si ces noms de colonnes proviennent de la table A ou B vous avez besoin d'accéder au DDL SQL qui définit le modèle de données .... ce qui nécessite d'analyser à nouveau SQL :). Avec l'AST et la table de symboles, vous pouvez générer du code de plusieurs façons, mais une méthode simple consiste à parcourir les AST et les constructions de traduction au fur et à mesure que vous les rencontrez. Cela ne permettra pas de construire des requêtes optimisées; cela nécessite une génération de code plus complexe, mais je m'attends à ce qu'elle soit adéquate si elle est prise en charge par les fonctions API appropriées que vous fournissez.

La génération de code réelle pouvait être effectuée en imprimant simplement du texte Java; Si vous suivez la route ANTLR, vous devrez faire quelque chose comme ça. Une alternative consiste à transformer littéralement les fragments de code SQL (sous forme d'ASTs) en fragments de code Java (sous forme d'ASTs). Ce dernier schéma vous donne plus de contrôle (vous pouvez réellement faire des transformations sur des fragments de code Java s'ils sont des ASTs) et, s'il est bien fait, peut être vérifié par un outil de génération de code.

Notre DMS Software Reengineering Toolkit serait une bonne base pour cela. DMS fournit un écosystème pour construire des outils de traduction, notamment des machines d'analyse robustes, un support de tables de symboles, des règles de traduction de modèles de syntaxe de surface et SQL (SQL 2011, le standard) comme analyseur disponible et testé. à utiliser du côté de la génération de code.

+0

Cela pourrait en fait être la meilleure réponse possible à ma question, bien que je commence à penser que ce sera une surcharge pour une petite bibliothèque open source. Mais ça a l'air très intéressant, en effet! Merci d'avoir répondu! –

Questions connexes