3

私は、SQL を外部 DSL として Java に「内部化」することを目的としたjOOQと呼ばれるデータベース抽象化ライブラリーを開発および保守しています。この取り組みの目標は、最も一般的な RDBMS の可能なすべての SQL 構文要素をタイプ セーフに構築および実行できるようにすることです。jOOQ の内部 DSL はますます複雑になってきており、正式に把握したいと考えています。アイデアは、入力としてSQLのある種の正式な定義を持てるようにしたいということです。

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 ::= ...

入力は、XML またはその他の記述的なメタ言語で定義することもできます。その入力を取得したら、その入力から、Java で定義された構文をモデル化する一連の Java インターフェイスを生成したいと考えています。インターフェイスの例は次のとおりです。

// 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...
}

上記のインターフェイスを使用すると、現在 jOOQ で既に許可されているように、Java で SQL クエリを作成できます。

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

また、特定のビルドの一部の構文要素を除外したいと思います。たとえば、MySQL 専用の jOOQ をビルドする場合、SQL MERGE ステートメントをサポートする必要はありません。

Java に DSL を正式に内部化および外部化するために、そのような一般的なアプローチを実装する既存のライブラリはありますか? それとも自分で巻くべきですか?

4

1 に答える 1

1

あなたが実際にやろうとしているのは、汎用 SQL を内部 API の呼び出しに変換することです。合理的なようです。

そのためには、「汎用 SQL」のパーサーと、そのパーサーからコードを生成する手段が必要です。通常、抽象的な構文ツリーを構築するにはパーサーが必要であり、シンボル テーブルがほとんど必要です (テーブル名とは何か、列名とは何か、それらの列名がテーブル A からのものかテーブル B からのものかを知るために、どこかでデータモデルを定義するSQL DDLにアクセスする必要があります.... SQLを再度解析する必要があります:)。

AST とシンボル テーブルを使用すると、さまざまな方法でコードを生成できますが、単純な方法は、AST をたどって変換構造に遭遇することです。これでは、最適化されたクエリを構築できません。より複雑なコード生成が必要ですが、提供する適切な API 関数でサポートされていれば十分だと思います。

実際のコード生成は、Java テキストを印刷するだけで実行できます。ANTLR ルートに行く場合は、次のようなことを行う必要があります。別の方法として、SQL コード フラグメント (AST として) を文字通り Java コード フラグメント (AST として) に変換する方法があります。後者のスキームでは、より詳細な制御が可能になり (Java コード フラグメントが AST の場合、実際に変換を行うことができます)、正しく行われた場合は、コード生成ツールでチェックできます。

DMS Software Reengineering Toolkitは、このための優れた基盤となります。DMS は、堅牢なパーサー機構、シンボル テーブルのサポート、表面構文パターン指向の変換ルールなど、翻訳ツールを構築するためのエコシステムを提供し、Java だけでなく、使用可能なテスト済みパーサーとして汎用 SQL (SQL 2011、標準) を備えています。コード生成側で使用します。

于 2011-12-02T16:31:53.697 に答える