takuさん、こんばんは
投稿ありがとうございます!
取り急ぎの確認ですが、DBMS は Oracle でよろしいでしょうか?
(PL/SQL とあるので多分そうだと思いますが念のため)
プロシージャは、カラムのデータ型よりもかなりバラエティに
富んでいるため、確認・実装が追っ付いてない部分もあります。
基本的に、JDBC の仕様としてサポートされていないものは、
デフォルトとして String になります。ただ、型の名前を見て、
調整できるものは調整していくというポリシーです。
ちょっとこちらでも確認してみますね。
2010/11/17 taku <mickey....@gmail.com>:
> --
> このメールは Google グループのグループ「DBFluteユーザの集い」の登録者に送られています。
> このグループに投稿するには、dbf...@googlegroups.com にメールを送信してください。
> このグループから退会するには、dbflute+u...@googlegroups.com にメールを送信してください。
> 詳細については、http://groups.google.com/group/dbflute?hl=ja からこのグループにアクセスしてください。
>
>
後で、また時間とってゆっくり調べてみようと思うのですが、
ぱっと調べた感じでは、情報があまり得られないので、
具体的に、なんのクラスにマッピングされるとうれしいか、
(CallableStatement でバインドするときに何でマッピングするのか)
などなど、takuさんの方で知ってる情報ありましたら頂けると幸いです。
#
# これから Oracle 10g XE の環境を起動して試してみます。
# (MacBook の VMWare 上の Windows なんですけど...)
#
2010/11/17 kubo <dbf...@gmail.com>:
なんとなくわかってきました。
(が、不安なので間違ってたら指摘して下さい)
DBMS_SQL.DATE_TABLE などは、
要は、この下のサイトでいう PL/SQL 表のことで、
最初からDBMS_SQLにパッケージされている
TYPEオブジェクトであると。
// PL/SQL コレクション型 | Shift the Oracle
http://www.shift-the-oracle.com/plsql/collection/
そして、JDBCから呼び出すには、どうしてもOracle依存の
JDBCドライバのクラスを利用しないといけない(かもしれない!?)。
// 配列をPL/SQLに渡してPL/SQL内でInsert処理を行う | @IT
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=38253&forum=12
これを前提とすると、DBFluteで実現するためには、
Sql2Entity の型マッピングで、
if (Oracle && dbTypeName.equals("PL/SQL TABLE")) {
// 型は List<配列の要素型>
}
という処理をして、その場合はバインド時にOracle依存の
クラスを使うようにする、という流れで実現できるかもです。
但し、環境的な制限として、以下と同じ形にはなります。
// Oracleの取扱い - Oracleの日付型の最適化 | DBFlute
http://dbflute.sandbox.seasar.org/ja/manual/reference/dbway/oracle/index.html#oracledate
また、「配列の要素型」がメタデータから取得できるか
どうかが課題で、dbTypeName が "PL/SQL TABLE" だけ
ってのはつらいですね。せめてTYPEオブジェクトの名前が
わからないとデータディクショナリからも探せないので。
(場合によっては、List<Object> 型になってしまう可能性も)
taku さん、ありがとうございます。
とりあえず色々とわかったことを書きます。
o メタデータから配列型名と配列要素型が取得できる
-> データディクショナリの USER_ARGUMENTS を検索
-> Sql2Entityでうまくやれば、List<String>, List<Integer>に
o Oracle依存のJDBCクラスを使えば呼び出しはできそう
-> 但し、ちょっと内部的な工事が必要
ということです。ですが、実際にJDBCレベルで試してみて、
幾つか課題があります。
A. DBMS_SQLの型だとArrayDescriptorが生成できない
-> ArrayDescriptor.createDescriptor("DBMS_SQL.NUMBER_TABLE", physConn)
-> 「名前パターンが無効です」という例外が発生する
-> create type ... で手動で作成したTYPEオブジェクトなら動作する
B. OUTパラメータでの取得ができない
-> cs.getArray(), cs.getObject() どちらでも内部で NullPointerException
-> まだ、ちょっと深く突っ込んでデバッグできていない
ということで、今の段階で机上でサポートできそうな機能は、
「手動で作ったTYPEオブジェクトのINパラメータ」
というところです。ひとまずこれを実装する方向で検討してみます。
(かなり込み入ってるので実装には時間が掛かると思います)
それが土台としてできてしまえば、A と B の問題さえ解決すれば、
すぐに同じく反映できると思います。
もし、A と B の情報が何かあれば提供して頂けると助かります。
dbflute-oracle-example (Oracle 10g XE) にて試しています。
replace-schema-50-procedure.sql の
o SP_TABLE_MANUAL_PARAMETER
o SP_TABLE_PACKED_PARAMETER
o SP_VARRAY_MANUAL_PARAMETER
というプロシージャがそのためのテストプロシージャで、
src/test/java 配下 VendorPlainTest クラスの
test_Procedure_ARRAY_Table_manual_Tx()
付近のメソッドが該当のテストです。
(リアルタイムで修正などしています)
2010/11/17 taku <mickey....@gmail.com>:
> また、TYPEオブジェクトについて1点懸念事項が・・・
> ネストされたTYPEオブジェクト(①TYPEオブジェクトの子要素にさらに②TYPEオブジェクトを設定している)の場合、
> 子要素の型、構成も取得できるのでしょうか?
>
> 例
> T_OBJECT 親TYPEオブジェクト ・・・ ①
> + V_VALUE VARCHAR2
> + N_VALUE NUMBER
> ┗ T_VALUE 子TYPEオブジェクト ・・・ ②
> + V_VALUE VARCHAR2
> ┗ N_VALUE NUMBER
こちら、具体的な create 文か何かありますでしょうか?
(配列の要素型がさらにTYPEオブジェクト???)
2010/11/18 taku <mickey....@gmail.com>:
taku さん、サンプルありがとうございます。
ちょっと、TYPEやARRAYやSTRUCT(OBJECT)が、
話の中に混じっているので、整理しますね。
TYPE は、要は独自型の定義と言えて、
ARRAYやSTRUCTを作成する際によく利用されると。
で、まずARRAYが一番最初に話題になって、
TABLE型、VARRAY型のパラメータを持つ
プロシージャを呼べるかどうか。
(どこまで自動化できるかどうか)
これはまさに今検討中で、
まず、"B" は解決しました。registerOutParameter()の第三引数に
TYPEオブジェクトの名前を指定することでうまく動作しました。
そして、Sql2Entity でメタデータを取得して、List<要素型>の
プロパティを作成するようにして、INパラメータ、OUTパラメータ
共に利用できるようになりました。必要な設定は、
既に紹介した「Oracleの日付型の最適化」と同じです。
(テスト中です)
"A" の問題は未着手です。さっぱり手がかりがない状態です。
(そもそも、DBMS_SQLの型を使ったパラメータを
Javaからどう呼ぶのか?)
そして、今度はSTRUCT(OBJECT)型ということですね。
ARRAYの要素型でのSTRUCTか、独立したSTRUCT型の
違いはありますが、どのみちSTRUCTはサポートしていません。
サポートするにしても、かなり時間が掛かると思われます。
但し、今回のARRAY対応で入れた仕組みに、多少の手動設定
を混ぜることで、呼び出すことは可能かもしれません。
ひとまず、一旦こんなところで。
また後でメール書きます。
2010/11/18 taku <mickey....@gmail.com>:
参考ページありがとうございます。
ただ、OTNのページは開けないですね...
(タイトルを見るに Google のキャッシュで見たかもしれません)
orafaq の方は、"A" とは関係なさそうですが、
「ARRAYの要素がSTRUCT」の話なので参考になります。
まあ、"A" に関しては、DBFluteを使う使わないに関わらず、
Javaでどうやって呼ぶのか?呼び出してる人がいるのか?
をどうにかしないとですね。逆にわかってしまえば、
単純な儀式で済むのであれば、DBFluteですぐに対応します。
TABLE(手動作成)、VARRAY に関しては、
要素型が通常のスカラ対応の型(文字列や数値など)において、
ProcedurePmbで他のデータ型と変わらず実行できるように
なりました。後ほど、SNAPSHOT公開しますね。
必要な設定は、以下の通り。
1. littleAdjustmentMap.dfprop にて、isAvailableDatabaseNativeJDBC = true
=> コンパイルレベルでOracleのJDBCドライバに依存させます
2. Seasar もしくは Commons DBCP 以外のDBCPの場合は、
DBFluteConfigにて、物理コネクションの取得コールバックの登録
"2" に関しては、Oracle のJDBCドライバがどうしても物理コネクション
を欲しがるので、そして、DBFluteはDataSourceをもらってるだけで、
物理コネクションがどれなのかは知らないので、そういったアプリの
環境に対応する「物理コネクション取得処理」をDBFluteに登録します。
ただ、Seasar や Commons DBCP を利用している場合は、
デフォルトの処理でなんとか物理コネクションを取得できるので、
特に設定は不要です。
そして、STRUCT対応ですが、
まず、直近では未対応。
将来的には、STRUCT対応のEntityを自動生成して、
STRUCTのパラメータを取り扱えるようにしたい、
というところですが、それも階層は1レベルまで、
とする予定です。STRUCTのパラメータ、もしくは、
ARRAYの要素のSTRUCTはスコープ内ですが、
STRUCT内のSTRUCTや、STRUCT内のARRAYなど
のネスト型は将来的にはスコープ外と考えています。
申し訳ないですが、サンプルの孫まである複雑な構造は
サポート対象外です。
(正確には自動化の対象外です、詳しくは以下を)
で、そういったプロシージャにおいては、
アプリの拡張次第で扱えるようにします。
結局、やるべきことというのが、以下の二つに集約されます。
o 自動生成時の、Entity構造の構築とプロパティの型の決定
o 実行時の、JDBCドライバ処理の調整(格闘)
まず、未サポートのデータ型は、プロシージャにおいては、
String ではなく、Object型にします。
そして、dbflute-oracle-exampleのArrayパラメータのある
プロシージャのProcedurePmbのBsクラスを見てもらうと
わかるのですが、そのパラメータで使う ValueType クラスを
指定できるようにしています。これと同じことでExクラスで
定義すれば、アプリで好きなように処理を挟むことができます。
自動化のメリットは半減しますが、一からCallableStatementと
格闘するよりかは幾分やりやすいかと思います。
複雑な構造に関しては、こういった「アプリ拡張での対応」
ができるようにします。
(今まさしく、この瞬間、整理してますのでお待ちを)
さらに余談で個人的な意見ですが、アプリとプロシージャの
インターフェースはできるだけシンプルに保つようにすることを
お奨めします。DBFluteでの上記のようなこともそうですが、
それに関わらず、というかDBFluteでもやりづらいということは
普通にJDBCでやってもやりづらいことに変わりはないので。
例えば、複雑な構造をパラメータに持つプロシージャを呼び出す
プロシージャを一つ作って、アプリから情報をもらって構築する、
逆にある程度の処理をアプリでやって、要の処理をプロシージャ
でやるようにするなど。データの取得場所を変えるなりして、
リファクタリングすれば、少しでもシンプルになる場所が
あるかもしれません。
とまあ、taku さんのプロジェクトの環境と状況がどうなっている
のかわからないので一般論として念のためのアドバイスです。
(もう、プロシージャを全く変更できない、増やせない状況、
とかがよくあるオチですが...)
2010/11/19 taku <mickey....@gmail.com>:
taku さん、ARRAYの対応をSNAPSHOTに反映しました。
http://dbflute.sandbox.seasar.org/ja/environment/newest.html
DBFlute-0.9.7.6-04-SNAPSHOT です。
EMechaからもダウンロードできます。ぜひお試し下さい。
テストは、dbflute-oracle-exampleにて行っています。
合わせてご覧になって下さい。
(さらにテストを進めたら RC も出すかもしれません)
もろもろのドキュメントはまだ未反映です。
リリースまでには整えようかなと思います。
(ValutTypeの指定などの拡張の仕方も含めて)
2010/11/19 kubo <dbf...@gmail.com>:
プロシージャでサポートする型について
取り急ぎですがドキュメントを書きました。
// ProcedurePmb - サポートされる型 | DBFlute
http://dbflute.sandbox.seasar.org/ja/manual/function/generator/task/sql2entity/procedurepmb.html#supportedtype
ValueType の指定の仕方なども載せています。
Object型で独自のValueTypeさえ設定さえすれば、
極端な話、どんな型でもJDBCでサポートされる限り
扱うことができます。
サポートされる型は、DBFluteの自動化の風にのって、
サポートされない型は、DBFluteの途中までの支援に加えて、
独自の調整を加える、というような感じです。
また、途中経過ですが、
OBJECT型(STRUCT型)対応のCustomizeEntityも
自動生成できるようになりました。
(プロシージャのパラメータとして定義されているものに限り)
TABLE型の要素でOBJECT型を使ってる場合も同じです。
実行時の処理がまだできていませんが、
これでも、何もない状態から独自の調整をするよりも、
とりあえずOBJECT対応のCustomizeEntityがある、
というだけでも有効な支援になるかなと思います。
(少なくともテンプレートになるかなと)
SNAPSHOT-05 が出ています。
taku さん、おはようございます。
こちらのドキュメントご覧下さい(書きかけ)。
http://dbflute.sandbox.seasar.org/ja/manual/reference/dbway/oracle/oraclearraystruct.html
そして、DBFlute0.9.7.6-RC1 が出ています。
ぜひお試し下さい。
2010/11/19 taku <mickey....@gmail.com>:
実装疲れから少し抜け出した jflute です。
taku さん、Oracleのバージョンは幾つでしょうか?
もし、Oracle 11g でしたら、ひとまずSql2Entityタスクが
正常に動作したことだけでも教えて頂けると助かります。
また、皆さん、Oracle 9i の環境をお持ちの方いらっしゃいましたら、
DBFlute0.9.7.6-RC1 で Sql2Entity を実行して例外がでないことを
確認して頂けると助かります。
ALL_TYPES、ALL_ARGUMENTS テーブルを参照しているのですが、
Oracle 9i や Oracle 11g でも同じ仕様なのかどうかが気になります。
(XE が 10g しかないのでこういったところの確認が大変ですね)
#
# 自動生成も実行時も込み入った処理をしていますので、
# 興味のある方はぜひソースを流し読みしてみて下さい。
# (真剣に読むと大変です)
# 自動生成では、
# o DfProcedureSupplementExtractorOracle
# o DfProcedurePmbSetupper
# がポイントです。
# ランタイムは OracleArrayType、OracleStructType ですね。
#
2010/11/22 kubo <dbf...@gmail.com>:
> #まだ斜め読みの最中ですが、TABLE型でのCLOBが対応されないのが凄い不思議です。
> #Oracleに詳しい方何かご存知でしたらぜひご教示願いたいです!
実際に、oracle.sql.ARRAY の属性の値に String 型を入れただけでは、
Oracleでの変換エラーになってしまいました。
通常のバインド変数では、String型のままでも扱えます。
ただし、4000文字(バイトだったかな!?)を超えると切れてしまう
という現象があるため、実際には Stream で扱います。
(要は、String型で扱うとVARCHARのつもりで
扱われてしまうというところですね)
StringClobType がまさしく該当するクラスです。
Statement の CharacterStream を利用しています。
そもそも大きなサイズを扱うということで、
当然と言えば当然の仕様とも言えます。
そういうこともあって、CLOBは
「ただのサイズ大きい文字列型」ではなく、
別のカラムとはかなり異なった種のものではあるので、
CLOBだけに「手こずる」ってのはシステム業界では
個人的にはあまり珍しくないことかなと思います。
にしても、扱えるようになりたいですね。
あまり深く突っ込めてないので、わかってしまえば簡単かも
しれません。というかできないわけないと、思いますしね。
ただ、TABLE型のCLOBという既に相当マニアックな領域に
来ているので、その「知ること」というのが大変ですね。
(ぱっとGoogleで検索しても全然情報がヒットしない)
Oracleに詳しいだけでもダメで、OracleのJDBCドライバに
詳しいだけでもダメで、OracleのTABLE型のJDBCドライバ
での扱いに詳しくないとなかなか情報ないでしょうねぇ...
ちなみに、やってるテストは以下のような感じです。
単なる文字列だと「内部表現の変換に失敗しました。」
という Oracle 内部でのエラーが出ます。
(oracle.sql.CLOBとか使うのかな!?)
conn = getDataSource().getConnection();
cs = conn.prepareCall("{call SP_TABLE_VARIOUS_PARAMETER(?, ?)}");
Connection physConn = ((ConnectionWrapper) conn).getPhysicalConnection();
ArrayDescriptor oracleDesc =
ArrayDescriptor.createDescriptor(typeName, physConn);
try {
ARRAY oracleArray = new ARRAY(oracleDesc, physConn, new String[] {
"foo", "bar" });
fail("oracleArray=" + oracleArray);
} catch (SQLException e) {
// Why?
log(e.getMessage());
}
とにもかくには、DBFluteではその情報が入り次第対応はします。
> CLOBを 「ただのサイズ大きい文字列型」と思っていました。。。
> StringではなくStreamで扱うということで、もの凄くシックリきました!
> 説明ありがとうございました。
サイズが大きい、ってのは実はそれだけでインパクトの
デカイものなんですね。さらには、インフラ的にも
表領域を別にするかどうか、など考慮すること一杯です。
http://www.shift-the-oracle.com/table/lob-storage.html
DB2 も、表スペース(Oracleの表領域!?)を作成するときに、
LARGEという、LOBデータを格納する専用の種別があるようです。
2010/11/23 taku <mickey....@gmail.com>:
別件の修正も入れて、DBFlute-0.9.7.6-RC2 を出しました。
EMechaもドキュメントのリンクも修正されています。
正式リリースは、来週半ばになる予定です。
できれば、それまでに一度でも動かしてもらえると助かります。
2010/11/23 kubo <dbf...@gmail.com>:
一つわかったことがあったので、修正しました。
http://dbflute.sandbox.seasar.org/ja/manual/reference/dbway/oracle/oraclearraystruct.html
「ARRAYの要素型の認識」ですが、
ALL_COLL_TYPES を使うことで、要素型を完全に認識させる
ことができるので、この制限は実質的になくなりました。
万が一、ALL_COLL_TYPESが利用できない、というような
環境があった場合のために、以前のやり方(ALL_ARGUMENTS技)
を保険的に残しています。(自動で切り替わります)
※ALL_COLL_TYPESがダメならALL_ARGUMENTSもダメかもだけど
これで、階層周りの制限というのがほぼ無くなったかなと。
(ARRAY<ARRAY<Xxx>> くらいかな)
Sybaseの話と並行して実装しているので、
同じく、DBFlute-0.9.7.6-14-SNAPSHOT に反映されています。
明後日、正式リリースされる予定です。
さらに、
o 別スキーマのTABLE型、OBJECT型を利用
o 別スキーマのプロシージャとTABLE型、OBJECT型
もサポートしました。
(追加スキーマを使います)
DBFlute-0.9.7.6-RC4 にて反映されています。
2010/11/29 kubo <dbf...@gmail.com>:
ひとまず、現段階での対応が反映された正式バージョン、
DBFlute-0.9.7.6 をリリースしました。
サポートされない利用の多くは、そもそもJDBCドライバで
どう扱うのかがわかっていないものです。
(情報頂ければ対応します...情報ないんですよねぇ...)
ただ、プロキシプロシージャを一つ作ってしまえば、
CLOB以外の制限は回避できるんじゃないかと。
// Oracleの配列・構造体パラメータ | DBFlute
http://dbflute.sandbox.seasar.org/ja/manual/reference/dbway/oracle/oraclearraystruct.html
実務で利用して頂けるとDBFluteが一番喜ぶのですが、
万が一なんらかの都合でそうできなかったとしても、
takuさんのおかげでDBFluteが一段と成長することが
できたので、本当に感謝感謝です。ありがとうございます。