[[構文解析記事一覧]] [[構文解析の記事一覧]] *目次 [#ie85c50a] #contents *JSqlParser [#z990ac26] http://jsqlparser.sourceforge.net/ SQLを解析してJavaクラスの階層構造に変換する **特徴 [#de654001] -Visitorパターンをつかったプログラミングが身に付くというか要求される。 Visitorパターンについて知りたい場合は下記のURLなどを見る Visitorパターンって、Visitorが訪れるイベントしかとれないようなのは、 ありがたくない気がする。 なぜなら、構文は開始を終了が明確になっていないと、構文木を生成できないからだ。 だったら、はじめからjparsecをつかってたほうがいいってことになる。 http://www.aerith.net/design/Visitor-j.html -Oracle特有の外部結合の(+)とかプレースホルダーとかは対応していないので、事前にちょいと整形が必要だ。 -ただ、SELECT文の場合とか、UPDATE文の場合とかを事前にこちら側で判断しておかないといけない仕組みになっている。まあ、SQLの文字列にSELECTやらUPDATEがはいっているとかで判断すればいいんだろうけど。おしゃれではない。 **使い方:準備 [#v0afcae4] ダウンロードしてきたjarのパスをzipに変換して解凍し、 そのなかからlibフォルダにjarがあるので、そいつをeclipseのビルドパスに外部jarとして取り込ませる。 **サンプル [#ye6afd41] サイトのサンプルがちょっと手直しが必要だったので直して、日本語訳しておきます。 TablesNamesFinderのStringValueはEclipseの自動補完を使うとjava.langの方をつかうので、 import net.sf.jsqlparser.expression.StringValue; としておきましょう JoinVisitor(だっけか?)は削除しておきます。 CCJSqlParserManager pm = new CCJSqlParserManager(); /* * Oracleのプレースホルダーは対応してないので、''で括るなどしましょう * :AAA -> ':AAA' * Oracleの外部結合である(+)も対応していないので、削っておきましょう * (+) -> 削除 */ String sql = "SELECT * FROM MY_TABLE1, MY_TABLE2, (SELECT * FROM MY_TABLE3) LEFT OUTER JOIN MY_TABLE4 "+ " WHERE ID = (SELECT MAX(ID) FROM MY_TABLE5) AND ID2 IN (SELECT * FROM MY_TABLE6)" ; net.sf.jsqlparser.statement.Statement statement = pm.parse(new StringReader(sql)); /* 対象のSQL文字列が何を行うか(たとえばSELECTなのかINSERTなのか...)に応じて、 StatementVisitorをimplementsで実装したクラスをつかってください。 とりあえずここでは例としてSELECT用のselectStatementをつかっています。 */ if (statement instanceof Select) { Select selectStatement = (Select) statement; TablesNamesFinder tablesNamesFinder = new TablesNamesFinder(); List tableList = tablesNamesFinder.getTableList(selectStatement); for (Iterator iter = tableList.iterator(); iter.hasNext();) { System.out.println(iter.next()); } } *感想 [#s3c3f85a] サンプルにJavaのコードのパース例とか載っているし、 BNFファイルのパース例とかが載っていて、興味深い。 この手のパースプログラムは、その他のパースプログラムの定義もどん欲に取り込もうとすると おもわれる。なぜなら移植したほうが、いちから作成するよりも簡単だからだ。 構文木を生成して、別の言語。特に自分自身の言語でのパース定義ソースを生成することが、 便利なのだろう。