この章では、Oracle SQLJ実装でユーザー定義SQL型がどのようにサポートされるかを説明します。ユーザー定義SQL型に対応するJavaクラスを生成できるOracle JPublisherユーティリティについても説明します。この章の最後には、Oracle OPAQUE型に関する項もあります。
この章では、次の項目について説明します。
ここでは、Oracle Database 11g のオブジェクトとコレクションの基本的な概念について説明します。
関連項目: 『Oracle Database SQL言語リファレンス』および『Oracle Databaseアドバンスト・アプリケーション開発者ガイド』. |
ここでは、次の項目について説明します。
Oracle SQLJ実装では、ユーザー定義のSQLオブジェクト型(複合データ構造体)、関連するSQLオブジェクト参照型およびユーザー定義のSQLコレクション型がサポートされています。Oracleのオブジェクトとコレクションは、複合データ構造体であり、複数のデータ要素で構成されます。
Oracle SQLJ実装では、強い型指定または弱い型指定の、Java表現のオブジェクト型、参照型およびコレクション型を、イテレータまたはホスト式で使用できます。強い型指定の表現では、特定のオブジェクト型、参照型またはコレクション型にマッピングするカスタムJavaクラスを使用しますが、このクラスはJava Database Connectivity (JDBC) 2.0標準のjava.sql.SQLData
インタフェース(オブジェクト型の場合のみ)またはOracleのoracle.sql.ORAData
インタフェースを実装する必要があります。どちらのインタフェースもOracle Database 11g JPublisherユーティリティでサポートされており、このユーティリティを使用するとカスタムJavaクラスを自動生成できます。
「強い型指定」という用語は、特定のJava型がSQL名前指定型またはユーザー定義型に対応付けられている場合に使用されます。たとえば、PERSON
型がある場合、対応するPerson
Javaクラスが対応付けられます。
弱い型指定の表現では、oracle.sql.STRUCT
(オブジェクトの場合)、oracle.sql.REF
(オブジェクト参照の場合)またはoracle.sql.ARRAY
(コレクションの場合)を使用します。弱い型指定の表現では、標準java.sql.Struct
、java.sql.Ref
またはjava.sql.Array
オブジェクトもかわりに使用できます。
「弱い型指定」という用語は、Java型が汎用的な方法で使用され、複数のSQL名前指定型にマップできる場合に使用されます。Javaクラス(インタフェース)には、SQL型に特有の情報はありません。これは、oracle.sql.STRUCT
、oracle.sql.REF
およびoracle.sql.ARRAY
型とjava.sql.Struct
、java.sql.Ref
およびjava.sql.Array
型の場合です。
コード中にOracle拡張型を使用する場合は、次の要件が伴うので注意してください。
Oracle JDBCドライバを使用する必要があります。
デフォルトのOracle固有コード生成を使用するか、またはISOコード生成の場合は必要に応じてプロファイルをカスタマイズします。Oracle固有生成コードの場合、プロファイルが生成されないため、カスタマイズは適用されません。Oracle JDBC Application Program Interface(API)は、生成されたJavaコードによって直接コールされます。
注意: デフォルトのカスタマイザoracle.sqlj.runtime.util.OraCustomizer を使用することをお薦めします。 |
アプリケーションの実行時にOracle SQLJランタイムを使用します。Oracle SQLJランタイムとOracle JDBCドライバは、Oracle拡張型をコード中に使用しない場合であっても、Oracleカスタマイザを使用する場合は常に必要です。
Oracle固有のセマンティクス・チェックを行うには、適切なチェッカを使用する必要があります。デフォルトのチェッカoracle.sqlj.checker.OracleChecker
は、フロントエンドとして機能し、環境に応じたチェッカを起動します。JDBCドライバを使用すると、Oracle固有のチェッカが起動されます。
注意: Oracleオブジェクトとコレクション用のOracle固有の型は、oracle.sql パッケージにあります。 |
カスタムJavaクラスの使用方法
この章では、主に、ユーザー定義型に対するカスタムJavaクラスの使用方法について説明します。ただし、ORAData
を実装したクラスは、他のOracle SQL型に対しても使用できます。ORAData
を実装したクラスを使用すると、SQLとJava間のデータ転送時に任意の処理または変換を実行できます。
SQLData
インタフェースは、カスタム・オブジェクト・クラス専用です。これに対し、ORAData
インタフェースは、どのカスタムJavaクラスにも使用できます。
用語上の注意
ユーザー定義のSQLオブジェクト型とSQLコレクション型は、ユーザー定義型(UDT)と呼ばれます。
オブジェクト、参照およびコレクションのカスタムJavaクラスは、それぞれカスタム・オブジェクト・クラス、カスタム参照クラスおよびカスタム・コレクション・クラスと呼ばれます。
関連項目: Oracleオブジェクトの特長と機能の概要は、『Oracle Databaseオブジェクト・リレーショナル開発者ガイド』を参照してください。 |
Oracle SQLオブジェクトは複合データ構造体であり、関連するデータ項目(各従業員に関する事実など)を1つのデータ単位にまとめたものです。オブジェクト型は、機能的にはJavaのクラスに相当します。Java型をインスタンス化してオブジェクトをいくつでも使用できるように、特定のオブジェクト型のオブジェクトをいくつでも設定して使用できます。
たとえば、CHAR
型の属性name
、CHAR
型のaddress
、CHAR
型のphonenumber
およびNUMBER
型のemployeenumber
を持つオブジェクト型EMPLOYEE
を定義できます。
Oracleのオブジェクトのメソッド(ストアド・プロシージャ)は、オブジェクト型への対応付けができます。これらのメソッドは、staticメソッドまたはインスタンス・メソッドとして、PL/SQLまたはJavaで実装できます。メソッドのシグネチャとして、任意の数の入力、出力または入出力パラメータを使用できます。すべては初期定義によって決まります。
Oracle SQLコレクションは、次の2つのカテゴリに分類されます。
どちらのカテゴリも1次元ですが、その要素として複合オブジェクト型を使用できます。VARRAY型は1次元配列に対して使用しますが、NESTED TABLE型は表に含まれる単一列の表に対して使用します。VARRAY型の変数をVARRAYと呼びます。NESTED TABLE型の変数をネストした表と呼びます。
VARRAYは、配列と同様、データ要素の順序付けられた集合であり、各要素が1つの索引を持ち、すべての要素のデータ型が同じです。VARRAYのサイズは、要素の最大数を示します。OracleのVARRAYは、名前が示すように可変サイズですが、VARRAY型の宣言時に、そのVARRAY型の最大サイズを指定する必要があります。
ネストした表は、順序付けされていない要素の集合です。表内のネストした表要素は、それ自体SQLで問合せを実行します。表と同じように、ネストした表の行数は、作成時に指定する必要はありません。行数は動的に算出されます。
注意: VARRAYの各要素またはネストした表内の各行は、ユーザー定義のオブジェクト型にすることが可能であり、ユーザー定義オブジェクト型の属性に対して、VARRAY型およびNESTED TABLE型を使用できます。Oracle Database 11gでは、コレクション型のネストをサポートしています。VARRAYの要素またはネストした表内の行を、別のVARRAY型またはNESTED TABLE型にすることも、VARRAY属性またはネストした表の属性を持つユーザー定義のオブジェクト型にすることもできます。 |
Oracle Database 11g では、ユーザー定義のオブジェクトおよびコレクション定義は、SQLのデータ型定義として機能します。これらのデータ型は、他のデータ型と同じように、表の列定義、SQLオブジェクトの属性定義およびストアド・プロシージャまたはストアド・ファンクションのパラメータの定義に使用できます。また、オブジェクト型を定義すると、そのオブジェクト参照型を他のSQL参照型のように使用できます。
たとえば、前の項のEMPLOYEE
Oracleオブジェクトを考えます。このオブジェクトを定義すると、Oracleのデータ型になります。NUMBER
型の表列と同じように、EMPLOYEE
型の表列を持つことができます。EMPLOYEE
列の各行に、EMPLOYEE
オブジェクト全体を格納できます。EMPLOYEE
オブジェクトへの参照で構成されるREF EMPLOYEE
型の列を持つこともできます。
同様に、NUMBER
のVARRAY(10)
としてVARRAY型MYVARR
を定義したり、CHAR(20)
のNESTED TABLE型NTBL
を定義できます。コレクション型MYVARR
とNTBL
はOracleのデータ型になるので、これらの型の列を表に定義できます。MYVARR
列の各行は、最大10数字を収容する配列です。NTBL
列の各行は20文字で構成されます。
カスタムJavaクラスはファーストクラスの型で、ユーザー定義SQL型に対する読取りおよび書込みを透過的に行う場合に使用できます。カスタムJavaクラスの用途は、SQLとJava間のデータの変換手段を提供し、データへのアクセスを可能にすることです。この機能は、特に、オブジェクトとコレクションのサポートにおいて、またはデータのカスタム変換を行う場合に重要です。
SQLJアプリケーションで使用するすべてのユーザー定義型に対して、カスタムJavaクラスを用意することをお薦めします。Oracle JDBCドライバではデータ変換にこのクラスのインスタンスが使用され、弱い型指定のoracle.sql.STRUCT
、oracle.sql.REF
およびoracle.sql.ARRAY
クラスを使用するも便利で、エラーも発生しにくくなります。
SQLJイテレータまたはホスト式で使用するには、カスタムJavaクラスにoracle.sql.ORAData
およびoracle.sql.ORADataFactory
インタフェース、または標準java.sql.SQLData
インタフェースを実装する必要があります。ここでは、これらのインタフェースとカスタムJavaクラス機能の概要を、次の項目について説明します。
ここでは、ORAData
およびORADataFactory
インタフェースと標準SQLData
インタフェースの指定について説明します。
Oracle Database 11g には、ユーザー定義型(oracle.sql.ORAData
およびoracle.sql.ORADataFactory
)に対するOracle固有のカスタムJavaクラス機能をサポートするための一連のAPIが含まれています。
以前この機能のために使用されていたoracle.sql.CustomDatum
およびoracle.sql.CustomDatumFactory
インタフェースは非推奨になりました。
Oracleには、oracle.sql.ORAData
インタフェースと関連するoracle.sql.ORADataFactory
インタフェースが用意されています。これらのインタフェースを使用して、Oracleのオブジェクト型、参照型およびコレクション型をカスタムJavaクラスにマッピングできます。
データの送信や取出しにはoracle.sql.Datum
オブジェクトの形式を使用し、元のデータは適切なoracle.sql.Datum
のサブクラス(oracle.sql.STRUCT
など)の形式にします。このデータはSQL形式のままです。oracle.sql.Datum
オブジェクトはラッパーとしてのみ機能します。
関連項目: 『Oracle Database JDBC開発者ガイドおよびリファレンス』 |
Java形式からSQL形式へのデータ変換に使用するtoDatum()
メソッドは、ORAData
インタフェースで指定します。このメソッドでは、接続オブジェクトを入力として見なし、データをoracle.sql.*
表現に変換します。JDBCドライバは、実行時に接続オブジェクトを使用して、型チェックと型変換を行います。ORAData
とtoDatum()
は、次のように指定します。
interface oracle.sql.ORAData { oracle.sql.Datum toDatum(java.sql.Connection c) throws SQLException; }
カスタムJavaクラスのインスタンスを作成し、SQL形式からJava形式に変換するcreate()
メソッドは、ORADataFactory
インタフェースで指定します。このメソッドは、入力としてDatum
オブジェクトを取り、このオブジェクトにはデータおよび型コード(基になるデータがSQL型であることを示すOracleTypes.RAW
など)が含まれます。このメソッドから戻されるカスタムJavaクラスのオブジェクトには、ORAData
インタフェースが実装されています。このオブジェクトは、入力されたDatum
オブジェクトからデータを取り出します。ORADataFactory
とcreate()
は、次のように指定します。
interface oracle.sql.ORADataFactory { oracle.sql.ORAData create(oracle.sql.Datum d, int sqlType) throws SQLException; }
ORAData
インタフェースとORADataFactory
インタフェース間の関係を確立するには、ORAData
インタフェースを実装したカスタムJavaクラスに、static getORADataFactory()
メソッドを実装する必要があります。このメソッドで戻されるオブジェクトは、ORADataFactory
インタフェースが実装されているので、カスタムJavaクラスのインスタンスの作成に使用できます。戻されたオブジェクト自体が、カスタムJavaクラスのインスタンスであることも可能であり、この場合、Oracle JDBCドライバは、必要に応じてそのcreate()
メソッドを使用して、さらにカスタムJavaクラスのインスタンスを生成します。
注意: JPublisherの出力は、ORAData インタフェースおよびそのtoDatum() メソッドと、ORADataFactory インタフェースおよびそのcreate() メソッドとを、1つのカスタムJavaクラスに実装できます。ただし、toDatum() とcreate() を別々のインタフェースに指定した場合は、それぞれを別個のクラスに実装することも可能になります。ORAData およびそのtoDatum() メソッドと、getORADataFactory() メソッドを1つのカスタムJavaクラスに実装する一方で、ORADataFactory およびそのcreate() メソッドを別個のファクトリ・クラスに実装することも可能です。ここでは、両方のインタフェースを1つのクラスに実装する場合について説明します。 |
JPublisherを使用するして-usertypes=oracle
を指定すると、JPublisherでカスタムJavaクラスが生成され、このクラスにはORAData
インタフェース、ORADataFactory
インタフェースおよびgetORADataFactory()
メソッドが実装されます。下位互換性を保つために、JPublisherの-compatible
オプションとともに-usertypes=oracle
を指定して、CustomDatum
およびCustomDatumFactory
インタフェースを使用することもできます。
関連項目: 『Oracle Database JPublisherユーザーズ・ガイド』 |
Oracle9iデータベースでは、oracle.jdbc.driver
クラスにかわってoracle.jdbc
インタフェースが導入されていました。そのため、カスタマイズされたオブジェクトへのアクセスに以前使用されていたoracle.sql.CustomDatum
およびoracle.sql.CustomDatumFactory
インタフェースは非推奨になり、かわりにoracle.sql.ORAData
およびoracle.sql.ORADataFactory
インタフェースを使用します。CustomDatum
インタフェースのように、これらを標準SQLData
インタフェースのOracle固有の代替インタフェースとして使用できます。CustomDatum
インタフェースは、下位互換性を保つために現在もサポートされています。
CustomDatum
およびCustomDatumFactory
は、次のように定義します。
public interface CustomDatum { oracle.sql.Datum toDatum( oracle.jdbc.driver.OracleConnection conn ) throws SQLException; public interface CustomDatumFactory { oracle.sql.CustomDatum create( oracle.sql.Datum d, int sqlType ) throws SQLException; }
接続conn
および型コードsqlType
は、ORAData
およびORADataFactory
で説明されているように使用されます。ただし、CustomDatum
では、標準Connection
型ではなく、必ずOracle固有のOracleConnection
型を使用してください。
標準JDBC 2.0には、構造化オブジェクト型をJavaクラスにマッピングし、変換するためのjava.sql.SQLData
インタフェースが提供されています。このインタフェースは、構造化オブジェクト型のみをマッピングの対象としているため、コレクションや配列などのSQL型はマッピングできません。
SQLData
インタフェースは、JDBC 2.0標準であり、readSQL()
メソッドを指定してデータをJavaオブジェクトに読み取る一方で、writeSQL()
メソッドを指定してJavaオブジェクトからデータベースに書き込みます。JPublisherを使用して-usertypes=jdbc
を指定するとJPublisherでカスタムJavaクラスが生成され、このクラスにはSQLData
インタフェースが実装されます。
標準SQLData
機能の追加詳細は、Sun社のJDBC 2.0以上のAPI仕様を参照してください。
Oracleオブジェクト・メソッドは、カスタムJavaクラスのラッパーから起動できます。基になるストアド・プロシージャの記述言語がPL/SQL、Javaのどちらであるか、またSQLに公開されているかどうかは、ユーザーには表示されません。
Javaのラッパー・メソッドでサーバー側メソッドを起動するには、サーバーと通信するための接続が必要です。接続オブジェクトは、明示的パラメータとして提供することも、別の方法で関連付けることも可能です。たとえば、カスタムJavaクラスの属性として提供します。ラッパー・メソッドで使用する接続オブジェクトを非静的属性とした場合、このラッパー・メソッドをカスタムJavaクラスのインスタンス・メソッドとすると、この接続にアクセスできます。JPublisherで生成したカスタムJavaクラスでは、この手法が採用されています。
Oracleオブジェクト・メソッドの出力および入出力パラメータに関しては、次のことに留意してください。ストアド・プロシージャ(SQLオブジェクト・メソッド)によって、ある引数の内部状態が変更された場合、ストアド・プロシージャに渡された実引数も変更されます。Javaで記述した場合、こうした現象は起こりません。JDBC出力パラメータがストアド・プロシージャ・コールから戻る場合、新規に作成されたオブジェクトに格納する必要があります。元のオブジェクト識別性は失われます。
出力または入出力パラメータをコール元に戻す場合は、パラメータを配列要素として渡す方法もあります。入出力パラメータの場合は、ラッパー・メソッドが入力として配列要素をとります。処理後、ラッパーによって出力が配列要素に代入されます。JPublisherで生成したカスタムJavaクラスでは、この手法が使用されます。つまり、出力または入出力パラメータをそれぞれ単一要素配列で渡します。
JPublisherを使用すると、デフォルトではラッパー・メソッドが実装されます。生成されたクラスには、SQLData
インタフェースまたはORAData
インタフェースが実装されており、このことが当てはまります。このデフォルトの機能を無効化するには、JPublisherの-methods
フラグをfalse
に設定します。
関連項目: 『Oracle Database JPublisherユーザーズ・ガイド』 |
注意: カスタムJavaクラスを実装する場合、ラッパー・メソッドを実装する方法としていくつかの選択肢があります。サーバーでのデータ処理には、SQLオブジェクト・メソッドによって直接実行する場合と、クライアントからサーバーへオブジェクト値を転送して、サーバー上でメソッドを実行する場合があります。JPublisherでのラッパー・メソッドの実装および実装による効果については、「JPublisherで生成されるラッパー・メソッド」を参照してください。 |
カスタムJavaクラスに求められる要件としては、有効なホスト変数型としてOracle SQLJトランスレータで認識できることおよびトランスレータで型チェックできることが挙げられます。
注意: ユーザー定義型用のカスタムJavaクラスは、このマニュアルで「ラッパー・クラス」と呼ばれている場合が多くあります。 |
ORADataを実装したクラスに対するOracleの要件
ORAData
を実装するためのOracleでの要件は、どのカスタムJavaクラスの場合にも基本的には同じです。ただし、クラスによるマッピング先が、オブジェクト、オブジェクト参照、コレクションまたはその他のSQL型のどれに該当するかによって、この要件は若干異なってきます。
この要件を次に示します。
oracle.sql.ORAData
インタフェースを実装したクラスであること。
oracle.sql.ORADataFactory
オブジェクトを戻り値とするgetORADataFactory()
メソッドを実装したクラスであること。メソッドのシグネチャは、次のように指定します。
public static oracle.sql.ORADataFactory getORADataFactory();
非推奨のCustomDatum
インタフェースを使用する場合、クラスでgetFactory()
メソッドを実装すること。このメソッドはoracle.sql.CustomDatumFactory
オブジェクトを戻します。メソッドのシグネチャは、次のように指定します。
public static oracle.sql.CustomDatumFactory getFactory();
クラスがString
定数_SQL_TYPECODE
を持ち、この定数が、toDatum()
から戻されるDatum
サブクラス・インスタンスのoracle.jdbc.OracleTypes
型コードに初期化されること。型コードを次に示します。
カスタム・オブジェクト・クラスの場合
public static final int _SQL_TYPECODE = OracleTypes.STRUCT;
カスタム参照クラスの場合
public static final int _SQL_TYPECODE = OracleTypes.REF;
カスタム・コレクション・クラスの場合
public static final int _SQL_TYPECODE = OracleTypes.ARRAY;
これ以外のクラスの場合は、それぞれ適切な型コードで初期化します。たとえば、カスタムJavaクラスで、RAW
フィールドに対してJavaオブジェクトをシリアライズおよびシリアライズ解除するには、_SQL_TYPECODE
をOracleTypes.RAW
に初期化します。
注意: OracleTypes クラスは、各Oracleデータ型の型コード(整数の定数)のみを定義します。標準SQL型のOracleTypes エントリは、標準java.sql.Types 型定義クラスのエントリと同じです。 |
_SQL_TYPECODE
がSTRUCT
、REF
またはARRAY
のいずれかに該当する(つまり、オブジェクト、オブジェクト参照またはコレクションを表す)カスタムJavaクラスの場合、該当のユーザー定義型の名前を示す定数を保持していること。次に例を示します。
カスタム・オブジェクト・クラスおよびカスタム・コレクション・クラスのString
定数_SQL_NAME
は、ユーザー定義型に対して宣言したSQL名に初期化する必要があります。次に例を示します。
public static final String _SQL_NAME = UDT name;
たとえば、ユーザー定義のPERSON
オブジェクトのカスタム・オブジェクト・クラスの定数は次のようになります。
public static final String _SQL_NAME = "PERSON";
次のように、必要に応じて、スキーマで同様に指定できます。
public static final String _SQL_NAME = "SCOTT.PERSON";
PERSON
オブジェクトのコレクションをPERSON_ARRAY
と宣言した場合のカスタム・コレクション・クラスの定数は、次のようになります。
public static final String _SQL_NAME = "PERSON_ARRAY";
カスタム参照クラスのString
定数_SQL_BASETYPE
は、参照先のユーザー定義型に対して宣言したSQL名に初期化する必要があります。
public static final String _SQL_BASETYPE = UDT name;
PERSON
参照のカスタム参照クラスの定数は、次のようになります。
public static final String _SQL_BASETYPE = "PERSON";
前述以外のORAData
で使用する場合、UDT名の指定はありません。
使用時には次の事項に注意してください。
コレクション型の名前は、ベース型ではなく、コレクション型を表す名前にします。たとえば、PERSON
オブジェクトに対し、VARRAYまたはNESTED TABLE型のPERSON_ARRAY
を宣言した場合は、_SQL_NAME
エントリに指定するコレクション型の名前は、PERSON
ではなく、PERSON_ARRAY
になります。
SQL型を_SQL_NAME
フィールドに指定するときに、SQL型が大/小文字を区別して(引用符で囲んで)宣言されている場合、CaseSensitive
やSCOTT.CaseSensitive
など、宣言されているとおりにSQL名を指定する必要があります。これは、引用符内で同様に名前の大/小文字を区別するJPublisher入力ファイルでの使用方法と異なります。SQL型を大/小文字を区別して宣言していない場合(引用符なし)、ADDRESS
やSCOTT.ADDRESS
のように、すべて大文字でSQL名を指定する必要があります。
JPublisherでは、大/小文字の区別とJPublisherの-omit_schema_names
設定がある場合はそれに従って、自動的にこのフィールドの値を生成します。
SQLDataを実装したクラスに対する要件
ISO SQLJ規格では、SQLData
インタフェースを実装するクラスへの型マップ定義の要件を概説しています。一方、SQLData
ラッパー・クラスは、public static final
フィールドでSQL関連オブジェクト型を識別できます。
次の点は重要なので、十分に注意してください。
マッピングの指定に型マップを使用する場合でも、標準でないpublic static final
フィールドを使用する場合でも、一貫して指定する必要があります。public static final
フィールドを不要にする目的ですべての関連マッピングを指定する型マップを使用するか、または型マップをまったく使用せずにすべてのマッピングをpublic static final
フィールドで指定します。
SQLData
は、ORAData
とは異なり、構造化オブジェクト型のマッピング専用です。オブジェクト参照やコレクションや配列などのSQL型のマッピングには、SQLDataを使用できません。ORAData
を使用しない場合、オブジェクト参照とコレクションをマッピングする方法は、それぞれ弱い型指定のjava.sql.Ref
とjava.sql.Array
、またはoracle.sql.REF
とoracle.sql.ARRAY
を使用する方法のみです。
SQL型からJava型へのマッピングを指定するとき、SQL型が大/小文字を区別する方法で宣言されている場合、CaseSensitive
またはSCOTT.CaseSensitive
など宣言されているとおりにSQL名を指定する必要があります。これは、引用符内で同様に名前の大/小文字を区別するJPublisher入力ファイルでの使用方法と異なります。SQL型を大/小文字を区別して宣言していない場合、ADDRESS
やSCOTT.ADDRESS
のように、すべて大文字でSQL名を指定する必要があります。
型マップ・リソースで指定したマッピング
まず、ISO SQLJ規格に従ったマッピング表現を想定します。Address
、pack.Person
およびpack.Manager.InnerPM
(InnerPM
はManager
の内部クラスです)がjava.sql.SQLData
を実装している3つのラッパー・クラスであるとします。
次の点を考慮する必要があります。
これらのクラスは、宣言済の接続コンテキスト型の明示的接続コンテキスト・インスタンスを使用する文でのみ採用する必要があります。たとえば、この型をSDContext
と呼ぶとします。
Address a =...; pack.Person p =...; pack.Manager.InnerPM pm =...; SDContext ctx = new SDContext(url,user,pwd,false); #sql [ctx] { ... :a ... :p ... :pm ... };
接続コンテキスト型は、java.util.PropertyResourceBundle
を実装している関連クラスを指定するwith
属性のtypeMap
で宣言されている必要があります。前述の例では、SDContext
が次のように宣言されています。
#sql public static context SDContext with (typeMap="SDMap");
型マップのリソースは、SQLオブジェクト型からjava.sql.SQLData
インタフェースを実装するJavaクラスにマッピングしている必要があります。このマッピングは、次の形式のエントリで指定します。
class.java_class_name=STRUCT sql_type_name
STRUCT
キーワードは省略可能です。例では、SDMap.properties
リソース・ファイルに次のエントリがあります。
class.Address=STRUCT SCOTT.ADDRESS class.pack.Person=PERSON class.pack.Manager$InnerPM=STRUCT PRODUCT_MANAGER
パッケージとクラス名の分割にはピリオド(.)を使用しますが、内部クラス名を分割するにはドル記号($)を使用する必要があります。
重要: デフォルトのOracle固有コード生成を使用している場合、コンテキスト型がSDContext の文に使用されるイテレータにも同じ型マップSDMap が宣言されていることが必要です。次に例を示します。
#sql public static iterator SDIter with (typeMap="SDMap"); ... SDContext sdctx = ... SDIter sditer; #sql [sdctx] sditer = { SELECT ...}; これにより、イテレータ・クラスに正しいコードが生成されたことを確認します。 |
マッピングを型マップ・リソースに指定するこのメカニズムは、非標準の方法よりも複雑になっています。さらに、型マップ・リソースをデフォルトの接続コンテキストと関連付けることはできません。すべてのマッピング情報が1つの場所、型マップ・リソースに置かれるというメリットがあります。つまり、コンパイル済アプリケーションでの型マッピングは、後で簡単に調整できます。たとえば、新規SQL型およびJavaラッパーを拡張SQL-Java型階層に含めることができます。
次の点に注意してください。
この機能を使用するには、SQLJ runtime12
またはruntime12ee
ライブラリを採用する必要があります。型マップはjava.util.Map
オブジェクトで表されます。これらは、SQLJランタイムAPIで公開されていますが、汎用ランタイム・ライブラリではサポートできません。
SQLData
ラッパー・クラスがSQLJ文のOUT
またはINOUT
パラメータに現れた場合、Oracle SQLJランタイムおよびOracle固有コード生成またはプロファイルのカスタマイズを使用する必要があります。これは、Oracle JDBCがそのようなパラメータのSQL型をregisterOutParameter()
で必要とするためです。さらに、OUT
パラメータ型を登録するため、SQL型は変換中に有力な型マップにより凍結されます。
SQLJ型マップは基礎となる接続で使用しているJDBC型マップとは独立しています。このため、SQLData
ラッパーを使用しているSQLJコードおよびJDBCコードを混在させている場合は、注意が必要です。しかし、指定されたSQLJ接続コンテキスト上の有効な型マップは、簡単に抽出できます。
ctx.getTypeMap();
ラッパー・クラスの静的フィールドで指定されたマッピング
SQLData
を実装しているクラスは、次の非標準要件を満たすことができます。
JavaクラスはString
定数_SQL_NAME
を宣言し、そこでJavaクラスによってラップされるSQL型の名前を定義します。例として、Address
クラスには次のようなフィールド宣言があります。
public static final String _SQL_NAME="SCOTT.ADDRESS";
次の宣言はpack.Person
内にあります。
public static final String _SQL_NAME="PERSON";
また、pack.Manager.InnerPM
クラスには次の要素があります。
public static final String _SQL_NAME="PRODUCT_MANAGER";
JPublisherでは、常に_SQL_NAME
フィールドとともにSQLData
ラッパー・クラスが生成されます。ただし、このフィールドは型マップを参照するSQLJ文では無視されます。
注意:
|
SQLJのコマンドラインには、カスタムJavaクラス(ORAData
またはSQLData
を実装)の.java
ファイルを、アプリケーションの.sqlj
ファイルと一緒に指定できます。ただし、この指定は、SQLJの-checksource
フラグをtrue
(デフォルト)に設定し、CLASSPATHにカスタムJavaソースの保存ディレクトリを指定した場合には必要ありません。
注意: ここでは、カスタム・オブジェクトとカスタム・コレクション用に、.sqlj ファイルではなく.java ファイルを作成していることを想定しています。.sqlj ファイルは、SQLJコマンドラインで指定される必要があります。 |
たとえば、ObjectDemo.sqlj
でOracleのオブジェクト型ADDRESS
およびPERSON
を使用し、これらのオブジェクトのカスタムJavaクラスが生成されている場合は、次のようにSQLJを実行できます。
-checksource=true
を指定し、CLASSPATHにカスタムJavaソースの保存ディレクトリを指定した場合は、次のようにします。
% sqlj ObjectDemo.sqlj
-checksource=false
を指定した場合は、次のようにします(この行は、全体を1行で入力します)。
% sqlj ObjectDemo.sqlj Address.java AddressRef.java Person.java PersonRef.java
また、Javaコンパイラを使用してカスタム.java
ソース・ファイルを直接コンパイルすることもできます。この場合は、.sqlj
ファイルの変換前に、コンパイルする必要があります。
注意: ORAData 実装はOracle固有の機能を必要とするため、トランスレータの移植設定を-warn=noportable (デフォルト)に設定する必要があり、この設定にしない場合は移植性に関する多数の警告がSQLJから通知されます。-warn フラグの詳細は、「トランスレータからの警告(-warn)」を参照してください。 |
カスタムJavaクラス・インスタンスを使用すると、Oracle SQLJおよびJDBC実装では、ユーザー定義型の読込みと書込みが可能になります(ただし、これらは組込み型です)。この仕組みをユーザーが意識することはありません。
ORAData
実装およびSQLData
実装でのデータの読込み/書込みの仕組みは、『Oracle Database JDBC開発者ガイドおよびリファレンス』を参照してください。
ここまでは、カスタムJavaクラスについて、次のような使用例を取り上げてきました。
SQLオブジェクトのラッパー: このカスタム・オブジェクト・クラスは、oracle.sql.STRUCT
インスタンスに対して使用します。
SQL参照のラッパー: このカスタム参照クラスは、oracle.sql.REF
インスタンスに対して使用します。
SQLコレクションのラッパー: このカスタム・コレクション・クラスは、oracle.sql.ARRAY
インスタンスに対して使用します。
これ以外のoracle.sql.*
型をラッピングする場合でも、カスタムJavaクラスを用意すると独自の変換または処理に役立つことがあります。このためには、次の例に示すように、ORAData
を実装したクラスを使用してください(SQLData
使用しません)。
データの暗号化と復号化、またはデータの妥当性チェックを行う場合
読込み後または書込み前の値をロギングする場合
CHAR列(URL情報を格納した文字フィールドなど)をより小さいコンポーネントに解析する場合
文字列を数値定数にマッピングする場合
データをより適切なJava形式にマッピングする場合(DATE
フィールドをjava.util.Date
形式にマッピングする場合など)
データ表現をカスタマイズする場合(選択した表のフィート単位データをメートル単位で表現する場合など)
Javaオブジェクトをシリアライズおよびシリアライズ解除する場合(RAW
フィールドなどに対して)
注意: このような機能は、SQLData インタフェースを使用しても実現されません。SQLData 実装でラッピング対象となるのは構造化オブジェクト型のみに限られているためです。 |
ORADataの一般的な使用方法: BetterDate.java
ここでは、ORAData
インタフェースを実装したクラスを使用して、Javaの日付をカスタマイズする方法を示します。これは、java.sql.Date
のかわりに使用できます。
注意: これは、完全なアプリケーションではありません。main() メソッドはありません。 |
import java.util.Date; import oracle.sql.ORAData; import oracle.sql.DATE; import oracle.sql.ORADataFactory; import oracle.jdbc.OracleTypes; // a Date class customized for user's preferences: // - months are numbers 1..12, not 0..11 // - years are referred to through four-digit numbers, not two. public class BetterDate extends java.util.Date implements ORAData, ORADataFactory { public static final int _SQL_TYPECODE = OracleTypes.DATE; String[]monthNames={"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; String[]toDigit={"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; static final BetterDate _BetterDateFactory = new BetterDate(); public static ORADataFactory getORADataFactory() { return _BetterDateFactory;} // the current time... public BetterDate() { super(); } public oracle.sql.Datum toDatum(java.sql.Connection conn) { return new DATE(toSQLDate()); } public oracle.sql.ORAData create(oracle.sql.Datum dat, int intx) { if (dat==null) return null; DATE DAT = ((DATE)dat); java.sql.Date jsd = DAT.dateValue(); return new BetterDate(jsd); } public java.sql.Date toSQLDate() { java.sql.Date retval; retval = new java.sql.Date(this.getYear()-1900, this.getMonth()-1, this.getDate()); return retval; } public BetterDate(java.sql.Date d) { this(d.getYear()+1900, d.getMonth()+1, d.getDate()); } private static int [] deconstructString(String s) { int [] retval = new int[3]; int y,m,d; char temp; int offset; StringBuffer sb = new StringBuffer(s); temp=sb.charAt(1); // figure the day of month if (temp < '0' || temp > '9') { m = sb.charAt(0)-'0'; offset=2; } else { m = (sb.charAt(0)-'0')*10 + (temp-'0'); offset=3; } // figure the month temp = sb.charAt(offset+1); if (temp < '0' || temp > '9') { d = sb.charAt(offset)-'0'; offset+=2; } else { d = (sb.charAt(offset)-'0')*10 + (temp-'0'); offset+=3; } // figure the year, which is either in the format "yy" or "yyyy" // (the former assumes the current century) if (sb.length() <= (offset+2)) { y = (((new BetterDate()).getYear())/100)*100 + (sb.charAt(offset)- '0') * 10 + (sb.charAt(offset+1)- '0'); } else { y = (sb.charAt(offset)- '0') * 1000 + (sb.charAt(offset+1)- '0') * 100 + (sb.charAt(offset+2)- '0') * 10 + (sb.charAt(offset+3)- '0'); } retval[0]=y; retval[1]=m; retval[2]=d; // System.out.println("Constructing date from string as: "+d+"/"+m+"/"+y); return retval; } private BetterDate(int [] stuff) { this(stuff[0], stuff[1], stuff[2]); } // takes a string in the format: "mm-dd-yyyy" or "mm/dd/yyyy" or // "mm-dd-yy" or "mm/dd/yy" (which assumes the current century) public BetterDate(String s) { this(BetterDate.deconstructString(s)); } // years are as '1990', months from 1..12 (unlike java.util.Date!), date // as '1' to '31' public BetterDate(int year, int months, int date) { super(year-1900,months-1,date); } // returns "Date: dd-mon-yyyy" public String toString() { int yr = getYear(); return getDate()+"-"+monthNames[getMonth()-1]+"-"+ toDigit[(yr/1000)%10] + toDigit[(yr/100)%10] + toDigit[(yr/10)%10] + toDigit[yr%10]; // return "Date: " + getDate() + "-"+getMonth()+"-"+(getYear()%100); } public BetterDate addDays(int i) { if (i==0) return this; return new BetterDate(getYear(), getMonth(), getDate()+i); } public BetterDate addMonths(int i) { if (i==0) return this; int yr=getYear(); int mon=getMonth()+i; int dat=getDate(); while(mon<1) { --yr;mon+=12; } return new BetterDate(yr, mon,dat); } // returns year as in 1996, 2007 public int getYear() { return super.getYear()+1900; } // returns month as 1..12 public int getMonth() { return super.getMonth()+1; } public boolean equals(BetterDate sd) { return (sd.getDate() == this.getDate() && sd.getMonth() == this.getMonth() && sd.getYear() == this.getYear()); } // subtract the two dates; return the answer in whole years // uses the average length of a year, which is 365 days plus // a leap year every 4, except 100, except 400 years = // = 365 97/400 = 365.2425 days = 31,556,952 seconds public double minusInYears(BetterDate sd) { // the year (as defined in the preceding text) in milliseconds long yearInMillis = 31556952L; long diff = myUTC()-sd.myUTC(); return (((double)diff/(double)yearInMillis)/1000.0); } public long myUTC() { return Date.UTC(getYear()-1900, getMonth()-1, getDate(),0,0,0); } // returns <0 if this is earlier than sd // returns = if this == sd // else returns >0 public int compare(BetterDate sd) { if (getYear()!=sd.getYear()) {return getYear()-sd.getYear();} if (getMonth()!=sd.getMonth()) {return getMonth()-sd.getMonth();} return getDate()-sd.getDate(); } }
ここでは、Oracle Database 11g のユーザー定義オブジェクト型とユーザー定義コレクション型の作成例および使用例を示します。
オブジェクト型を作成するSQLコマンドは、次の形式で指定します。
CREATE TYPE typename AS OBJECT ( attrname1 datatype1, attrname2 datatype2, ... ... attrnameN datatypeN );
typename
で、オブジェクト型の名前を指定します。attrname1
からattrnameN
で、属性名を指定します。datatype1
からdatatypeN
で、属性のデータ型を指定します。
次に、Oracle Database 11g におけるユーザー定義オブジェクト型の作成例を示します。
この例では、SQLを使用して次の項目を作成します。
2つのオブジェクト型、PERSON
とADDRESS
。
PERSON
オブジェクト用の型付けされた表。
EMPLOYEES
表。ADDRESS
列が1列とPERSON
参照列が2列あります。
これらの項目を作成するスクリプトを次に示します。
/*** Using user-defined types (UDTs) in SQLJ ***/ / /*** Create ADDRESS UDT ***/ CREATE TYPE ADDRESS AS OBJECT ( street VARCHAR(60), city VARCHAR(30), state CHAR(2), zip_code CHAR(5) ) / /*** Create PERSON UDT containing an embedded ADDRESS UDT ***/ CREATE TYPE PERSON AS OBJECT ( name VARCHAR(30), ssn NUMBER, addr ADDRESS ) / /*** Create a typed table for PERSON objects ***/ CREATE TABLE persons OF PERSON / /*** Create a relational table with two columns that are REFs to PERSON objects, as well as a column which is an Address ADT. ***/ CREATE TABLE employees ( empnumber INTEGER PRIMARY KEY, person_data REF PERSON, manager REF PERSON, office_addr ADDRESS, salary NUMBER ) /*** Insert some data--2 objects into the persons typed table ***/ INSERT INTO persons VALUES ( PERSON('Wolfgang Amadeus Mozart', 123456, ADDRESS('Am Berg 100', 'Salzburg', 'AT','10424'))) / INSERT INTO persons VALUES ( PERSON('Ludwig van Beethoven', 234567, ADDRESS('Rheinallee', 'Bonn', 'DE', '69234'))) / /** Put a row in the employees table **/ INSERT INTO employees (empnumber, office_addr, salary) VALUES ( 1001, ADDRESS('500 Oracle Parkway', 'Redwood Shores', 'CA', '94065'), 50000) / /** Set the manager and PERSON REFs for the employee **/ UPDATE employees SET manager = (SELECT REF(p) FROM persons p WHERE p.name = 'Wolfgang Amadeus Mozart') / UPDATE employees SET person_data = (SELECT REF(p) FROM persons p WHERE p.name = 'Ludwig van Beethoven')
注意: Oracle SQL実装では、特にユーザー定義型の表にアクセスする場合に、表の別名(この例のp など)の使用を習慣付けることをお薦めします。オブジェクトの属性にアクセスする場合は、この構文を使用する必要があります。別名を使用する必要のない場合でも、別名の使用によって明確化できます。表の別名の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。 |
コレクションは、次の2つの種類があります。
可変長配列(VARRAY)
ネストした表(NESTED TABLE)
VARRAY型を作成するSQLコマンドは、次の形式で指定します。
CREATE TYPE typename IS VARRAY(n) OF datatype;
typename
でVARRAY型の名前を、n
で配列内の最大要素数を、またdatatype
で配列要素のデータ型を指定します。次に例を示します。
CREATE TYPE myvarr IS VARRAY(10) OF INTEGER;
NESTED TABLE型を作成するSQLコマンドは、次の形式で指定します。
CREATE TYPE typename AS TABLE OF datatype;
typename
でネストした表型の目的の名前を指定し、datatype
で表要素のデータ型を指定します。データ型は標準データ型だけでなく、ユーザー定義型も指定できます。ネストした表は1列のみに限られていますが、1つの列型を、複数の属性を持つ複合オブジェクトにすることも可能です。ネストした表には、データベース表と同様に、行数制限がありません。次に例を示します。
CREATE TYPE person_array AS TABLE OF person;
このCREATE TYPEコマンドを指定すると、PERSON
オブジェクトから構成された各行にNESTED TABLE型が作成されます。
次に、Oracle Database 11g におけるユーザー定義のコレクション型およびオブジェクト型の作成例を示します。
SQLを使用して次の項目が作成および設定されます。
2つのオブジェクト型PARTICIPANT_T
およびMODULE_T
コレクション型MODULETBL_T
(MODULE_T
オブジェクトのネストした表)
PARTICIPANT_T
参照の列およびネストした表のMODULETBL_T
列を含むPROJECTS
表
コレクション型PHONE_ARRAY
(VARCHAR2(30)
のVARRAY)
PERSON
とADDRESS
オブジェクト(「オブジェクト型の作成」に同じ定義が示されています)
EMPLOYEES
表(PHONE_ARRAY
列を含む)
これらの項目を作成するスクリプトを次に示します。
Rem This is a SQL*Plus script used to create schema to demonstrate collection Rem manipulation in SQLJ CREATE TYPE PARTICIPANT_T AS OBJECT ( empno NUMBER(4), ename VARCHAR2(20), job VARCHAR2(12), mgr NUMBER(4), hiredate DATE, sal NUMBER(7,2), deptno NUMBER(2)) / SHOW ERRORS CREATE TYPE MODULE_T AS OBJECT ( module_id NUMBER(4), module_name VARCHAR2(20), module_owner REF PARTICIPANT_T, module_start_date DATE, module_duration NUMBER ) / SHOW ERRORS CREATE TYPE MODULETBL_T AS TABLE OF MODULE_T; / SHOW ERRORS CREATE TABLE projects ( id NUMBER(4), name VARCHAR(30), owner REF PARTICIPANT_T, start_date DATE, duration NUMBER(3), modules MODULETBL_T ) NESTED TABLE modules STORE AS modules_tab; SHOW ERRORS CREATE TYPE PHONE_ARRAY IS VARRAY (10) OF varchar2(30) / /*** Create ADDRESS UDT ***/ CREATE TYPE ADDRESS AS OBJECT ( street VARCHAR(60), city VARCHAR(30), state CHAR(2), zip_code CHAR(5) ) / /*** Create PERSON UDT containing an embedded ADDRESS UDT ***/ CREATE TYPE PERSON AS OBJECT ( name VARCHAR(30), ssn NUMBER, addr ADDRESS ) / CREATE TABLE employees ( empnumber INTEGER PRIMARY KEY, person_data REF person, manager REF person, office_addr address, salary NUMBER, phone_nums phone_array ) /
Oracleでは、Oracleのオブジェクト型、参照型およびコレクション型を強い型指定のパラダイムのJavaクラスに柔軟にマッピングできます。開発者は、これらのカスタムJavaクラスを次の方法で作成できます。
OracleのJPublisherユーティリティでカスタムJavaクラスを自動生成し、このクラスを変更せずにそのまま使用する方法
JPublisherでカスタムJavaクラスと対応するサブクラス(後でユーザーが機能を変更できる)を自動生成する方法
JPublisherを使用せずに、手動でカスタムJavaクラスをコーディングする方法(「カスタムJavaクラスの要件」の要件を満たすクラスの場合のみ)
カスタムJavaクラスは手動でもコーディングできますが、JPublisherで生成されたクラスを直接使用すること、またはJPublisherで生成されたサブクラスを変更することをお薦めします。
JPublisherでは、Oracle oracle.sql.ORAData
または標準java.sql.SQLData
インタフェースを実装したカスタム・オブジェクト・クラスを生成できます。このうちのORAData
実装をJPublisherで生成した場合は、カスタム参照クラスも一緒に生成されます。現行より古いJDBCバージョンとの互換性のために、JPublisherで、非推奨のoracle.sql.CustomDatum
インタフェースを実装するクラスを生成することもできます。
SQLData
インタフェースは、カスタム参照クラスやカスタム・コレクション・クラスには実装できません。これから開発するコードを移植可能にする方法は、弱い型指定の標準java.sql.Ref
オブジェクトとjava.sql.Array
オブジェクトを、それぞれ参照とコレクションにマッピングする方法のみです。
ここでは、次の項目について説明します。
関連項目:
|
JPublisherを使用してカスタムJavaクラスを生成する場合は、ORAData
(カスタム・オブジェクト・クラス、カスタム参照クラスまたはカスタム・コレクション・クラス用)またはSQLData
(カスタム・オブジェクト・クラス専用)実装を使用できます。ORAData
実装には、ORADataFactory
インタフェース(カスタムJavaクラスのインスタンス生成に必要なインタフェース)も実装できます。
JPublisherの-usertypes
オプションの設定内容に応じて、実装の対象が決まります。-usertypes=oracle
設定ではORAData
実装が指定され、-usertypes=jdbc
設定ではSQLData
実装が指定されます。
ORAData実装
ユーザー定義オブジェクト型を処理対象としてJPublisherを実行し、カスタム・オブジェクト・クラスに対してORAData
実装を使用すると、次のようなクラスが自動的に生成されます。
カスタム・オブジェクト・クラス(通常は.sqlj
ソース・ファイル内)。Oracleのオブジェクト型に対応する型定義です。
このクラスには、各属性のアクセッサ・メソッドがあります。たとえば、getFoo()
およびsetFoo()
は、属性foo
のアクセッサ・メソッドです。JPublisherのデフォルトでは、サーバー側Oracleオブジェクトのメソッドを起動するラッパー・メソッドもクラスに生成されます。ただし、-methods=false
を設定すると、このラッパー・メソッドを生成しないように指定できます。この場合、JPublisherは、ラッパー・メソッドを生成せずに、カスタム・オブジェクト用に.sqlj
ファイルではなく.java
ファイルを作成します。
Oracleオブジェクト型へのオブジェクト参照にアクセスするためのカスタム参照クラス。
このカスタム参照クラスのgetValue()
メソッドは、カスタム・オブジェクト・クラスのインスタンスを戻り値としており、もう1つのsetValue()
メソッドは、カスタム・オブジェクト・クラスのインスタンスを入力として取り、データベース内のオブジェクトの値を更新します。
SQLオブジェクト型で参照を使用しているかどうかにかかわらず、強い型指定の参照クラスが常に生成されます。
最上位オブジェクトのオブジェクト属性またはコレクション属性にアクセスするためのカスタム・クラス。
Javaでは、最上位クラスのインスタンスを作成するとき、このクラスを使用して属性を作成します。
ユーザー定義コレクション型を処理対象としてJPublisherを実行し、ORAData
を実装するように指定すると、次のようなクラスが自動的に生成されます。
カスタム・コレクション・クラス。指定したOracleコレクション型に対応する型定義として機能します。
このカスタム・コレクション・クラスのオーバーロード・メソッドgetArray()
およびsetArray()
は、コレクション単位で取得や更新を行うメソッドであり、getElement()
メソッドおよびsetElement()
メソッドは、コレクションの要素単位で取得や更新を行うメソッドです。このクラスには、これ以外のユーティリティ・メソッドもあります。
要素のカスタム・オブジェクト・クラス(コレクションの要素がオブジェクトの場合)。
Javaでは、コレクションのインスタンスを作成するときに、このクラスを使用してオブジェクト要素を作成します。
JPublisherで生成したこの2種類のカスタムJavaクラスには、ORAData
インタフェース、ORADataFactory
インタフェースおよびgetORADataFactory()
メソッドが実装されます。
注意:
|
ORAData実装のための強い型指定のオブジェクト参照
OracleのORAData
を実装する場合、JPublisherでは、弱い型指定のoracle.sql.REF
クラスを使用するのではなく、常に強い型指定のオブジェクト参照クラスを生成します。これによって、オブジェクト参照が強い型指定されている場合、型の安全性が向上し、SQLの動作がミラー化されます。強い型指定のクラス(PERSON
オブジェクトを参照するPersonRef
などの名前とともに使用)は、基本的にはREF
クラス用のラッパーです。
これらの強い型指定のREF
ラッパーには、参照されるSQLオブジェクトのインスタンスを対応するJavaクラスのインスタンスの形式で生成するgetValue()
メソッドがあります。(継承する場合は、対応するJavaクラスのサブクラスのインスタンスとして生成することになります。)たとえば、PERSON
SQLオブジェクト型と対応するPerson
Javaクラスがある場合、PersonRef
Javaクラスも存在します。PersonRef
クラスのgetValue()
メソッドは、データベース内のPERSON
オブジェクトのデータを含むPerson
インスタンスを戻します。
SQLオブジェクト型にオブジェクト参照の属性がある場合、そのオブジェクト型に対応するJavaクラスには、該当の参照型に対応するJavaクラスのインスタンスの属性があります。たとえば、MANAGER REF
属性のPERSON
オブジェクトがある場合、対応するPerson
JavaクラスはManagerRef
属性を持ちます。
SQLData実装
ユーザー定義型のオブジェクト型を処理対象としてJPublisherを実行し、カスタム・オブジェクト・クラスに対してSQLData
実装を選択する場合、Oracleオブジェクト型に対応する型定義として機能するカスタム・オブジェクト・クラスが生成されます。このカスタム・コレクション・クラスに属するものを次に示します。
各属性のアクセッサ・メソッド
標準SQLData
インタフェースのreadSQL()
メソッドとwriteSQL()
メソッドの実装
サーバー側で実行されるOracleオブジェクト・メソッドを起動するラッパー・メソッド(JPublisher実行時の設定が-methods=false
以外の場合)
ただし、SQLData
インタフェースはオブジェクトのみを対象とし、参照やコレクションには使用できないため、Oracleオブジェクト型を参照するためのカスタム参照クラスについては、JPublisherでは生成の対象とはしていません。弱い型指定の標準java.sql.Ref
インスタンスまたはoracle.sql.REF
インスタンスを使用する場合、移植性を気にする必要はありません。REF
インスタンスは、カスタム参照クラスのインスタンスと同様に、Oracle拡張メソッドgetValue()
およびsetValue()
を使用して、参照するオブジェクトのインスタンスに対して読込みと書込みを行います。標準Ref
インスタンスには、こうした読込みと書込みの機能はありません。
同様に、カスタム・コレクション・クラスに対してはSQLData
実装を使用できないため、弱い型指定の標準java.sql.Array
インスタンスを使用するか、または移植性が必要でなければoracle.sql.ARRAY
インスタンスを使用してください。Array
インスタンスとARRAY
インスタンスは、カスタム・コレクション・クラスのインスタンスと同様に、getArray()
機能を備えているため、コレクションの全体または一部の読取りはできますが、要素レベルでのアクセスおよび書込みはできません(このアクセスや書込みには、カスタム・コレクション・クラスのgetElement()
メソッドとsetElement()
メソッドを使用する必要があります)。
注意: JDBCの仕様では、SQLData インタフェースが移植可能であると定義されています。ただし、JPublisherで生成されるSQLData 実装を移植可能とするには、Oracle固有の機能とOracle型のマッピングを使用しないようにします(これらを使用した場合は、Oracle固有のoracle.sql.* クラスが使用されるためです)。 |
ここでは、JPublisherのコマンドラインの主要機能について説明します。主要機能として、Javaにマッピングするユーザー定義型を指定する機能、およびオブジェクト・クラス名、コレクション・クラス名、属性型のマッピングおよびラッパー・メソッドを指定する機能があります。次に、要点をまとめます。
JPublisherの-usertypes
オプションを介して、使用する実装を指定します。
Javaにマッピングするユーザー定義型の指定。使用するJPublisherのカスタム・オブジェクト・クラスとカスタム・コレクション・クラスの名前を指定することも、デフォルトの名前を使用することも可能です。必要に応じてJPublisherの-sql
、-user
および-case
オプションを使用します。
オプションとして、-numbertypes
、-builtintypes
および-lobtypes
などのJPublisherの-
xxx
types
オプションを介して属性型マッピングを指定します。
ラッパー・メソッド(Oracleオブジェクト・メソッドなど)の作成要否も指定できます。デフォルトでは作成されますが、JPublisherの-methods
フラグでの指定も可能です。
注意: これ以降は、カスタム参照クラスやカスタム・コレクション・クラスを簡潔に説明するために、ORAData 実装についてのみ記述します。 |
生成されたクラスへの実装の選択
JPublisherを実行する前に、OracleのORAData
インタフェースと標準SQLData
インタフェースのどちらを生成されたクラスに実装するかを検討します。SQLData
を使用すると、コードの移植性が高くなりますが、ORAData
を使用すると、型マップが不要になるなどいくつかのメリットがあります。
次の点に注意してください。
カスタム・コレクション・クラスには、ORAData
実装を使用する必要があります。SQLData
インタフェースではコレクションをサポートしていません。
強い型指定の参照クラスでは、常にORAData
カスタム・オブジェクト・クラスの実装が生成され、SQLData
カスタム・オブジェクト・クラスの実装は生成されません。SQLDataインタフェースは、強い型指定のオブジェクト参照をサポートしていません。かわりに、弱い型指定のjava.sql.Ref
型またはoracle.sql.REF
型を使用してください。
JPublisher -usertypes
オプションを使用して、クラスに実装するインタフェースを指定します。-usertypes=oracle
設定(デフォルト)ではORAData
インタフェースが指定され、-usertypes=jdbc
設定ではSQLData
インタフェースが指定されます。
次に示すJPublisherのコマンドラインは、それぞれORAData
、CustomDatum
およびSQLData
を実装する例です(%
はシステム・プロンプトです)。
% jpub -usertypes=oracle ... <other option settings> % jpub -usertypes=oracle -compatible=customdatum ... <other option settings> % jpub -usertypes=jdbc ... <other option settings>
-usertypes=jdbc
の場合、-compatible=customdatum
または-compatible=oradata
設定はJPublisherでは無視されます。
JPublisherでカスタムJavaクラスを作成する場合は、Javaにマッピングするユーザー定義SQL型を-sql
オプションで指定します。カスタム・オブジェクト・クラスとカスタム・コレクション・クラスの名前を指定することも、デフォルト名を使用することも可能です。
最上位カスタム・クラス(-sql
オプションで名前を指定したユーザー定義型に対応するクラス)のデフォルト名には、JPublisherコマンドラインで入力したユーザー定義型の名前が使用されます。データベース内のSQL名はデフォルトでは大/小文字が区別されないため、SQL名を大文字で開始することによって、Java規則に従ってクラス名を大文字で開始できます。たとえば、employee
オブジェクトのカスタム・クラスを作成するには、次のようにJPublisherを実行します。
% jpub -sql=Employee ...
employee
オブジェクトの属性であるhome_address
オブジェクトなど、他のクラスのデフォルト名は、JPublisherの-case
オプションで指定します。-case
オプションを指定しないと、mixed
に設定されます。つまり、カスタム・クラスのデフォルト名は、ユーザー定義型名の頭文字と以降の各ワードの頭文字が大文字になります。JPublisherでは、アンダースコア(_)、ドル記号($)、およびJavaの識別子で無効な文字は、ワード間のセパレータとしてみなされます。これらの文字は処理時に破棄されます。
たとえば、Oracleのオブジェクト型home_address
の場合は、クラスHomeAddress
がHomeAddress.sqlj
または.java
のソース・ファイルに生成されます。
JPublisherのコマンドラインでは、-sql
オプションに次の構文を使用します。
-sql=udt1<:mapclass1><,udt2<:mapclass2>>,...,<udtN<:mapclassN>> ...
単一のオプション設定で複数のアクションを指定できることに注意してください。
データベース・スキーマを指定するには、-user
オプションを使用します。次に例を示します。
% jpub -sql=Myobj,mycoll:MyCollClass -user=scott
Enter scott password: password
注意: カンマの前後に空白を挿入しないでください。 |
このように入力すると、OracleのオブジェクトはMYOBJ
という名前になり、Myobj
クラスを定義したMyobj.sqlj
ソース・ファイルが生成されます。また、MYCOLL
Oracleコレクションに対して、MyCollClass
クラスを定義したソース・ファイルMyCollClass.java
が生成されます。
-sql
にはスキーマ名(次の例のscott
スキーマなど)も指定できます。
% jpub -sql=scott.Myobj,scott.mycoll:MyCollClass -user=scott
Enter scott password: password
カスタム参照クラスの名前は指定できません。JPublisherでは、カスタム・オブジェクト・クラス名の後ろにRef
が追加されて、自動的に生成されます。これは、ORAData
実装の場合のみです。たとえば、Myobj
カスタム・オブジェクト・クラスを定義するMyobj.sqlj
Javaソース・ファイルをJPublisherで作成すると、MyobjRef
カスタム参照クラスを定義するMyobjRef.java
Javaソース・ファイルも生成されます。
注意: スキーマ(例のようにscott など)を指定しても、カスタムJavaクラスの名前には取り込まれません。 |
「ユーザー定義データ型」で定義したオブジェクト型とコレクション型のカスタムJavaクラスを作成するには、次のようにJPublisherを実行します。
% jpub -user=scott -sql=Address,Person,Phone_array,Participant_t,Module_t,Moduletbl_t
Enter scott password: password
または、カスタム・オブジェクト・クラスとカスタム・コレクション・クラスの名前を明示的に指定し、次のように実行します。
% jpub -user=scott -sql=Address,Person,phone_array:PhoneArray,
participant_t:ParticipantT,module_t:ModuleT,moduletbl_t:ModuletblT
Enter scott password: password
前述の2つの例はそれぞれ折り返されて表示されていますが、1行で入力されたコマンドラインです。
2番目の例では、Javaソース・ファイルAddress.sqlj
、AddressRef.java
、Person.sqlj
、PersonRef.java
、PhoneArray.java
、ParticipantT.sqlj
、ParticipantTRef.java
、ModuleT.sqlj
、ModuleTRef.java
およびModuletblT.java
が生成されます。ソース・ファイルの例は、「JPublisherのカスタムJavaクラスの例」を参照してください。
カスタムJavaクラスの設定方法を特定するために、JPublisherは指定されたスキーマに接続し、指定されたオブジェクト型の属性または指定されたコレクション型の要素を調べます。
注意: 単一の-sql 設定に複数のマッピングを指定するかわりに、同一のコマンドラインに複数の-sql オプションを使用できます。複数の-sql オプションの効果は累積されます。 |
JPublisherで生成するメソッドおよび属性のデフォルト名の大/小文字の使用方法を変更するには、-case
オプションを使用します(オブジェクトまたはコレクションが属性の場合、つまり下位カスタムJavaクラスの場合も、このオプションを使用します)。次の4通りの設定があります。
-case=mixed
(デフォルト)
大文字になる文字は、クラス名を構成する各ワードの頭文字、属性名を構成する各ワードの頭文字およびメソッド名の2番目以降のワードの頭文字です。これ以外の文字はすべて小文字になります。JPublisherでは、アンダースコア(_)、ドル記号($)、およびJavaの識別子で無効な文字は、ワード間のセパレータとしてみなされます。これらの文字は処理時に破棄されます。
-case=same
大/小文字区別は、データベース内での表現と同じになります。アンダースコアとドル記号は保持され、無効な文字は破棄されます。
-case=upper
小文字が大文字に変換されます。アンダースコアとドル記号は保持され、無効な文字は破棄されます。
-case=lower
大文字が小文字に変換されます。アンダースコアとドル記号は保持され、無効な文字は破棄されます。
注意: JPublisherの実行時にJavaにマッピングするユーザー定義型を指定しないと、スキーマ内のすべてのユーザー定義型が処理されます。最上位カスタム・クラスとその他のクラス(オブジェクトの属性またはコレクションの要素)のクラス名は、-case オプションに基づき生成されます。 |
JPublisherには、ユーザー定義型およびその属性型や要素型をSQLとJavaとの間でマッピングする方法が数通りあります。
JPublisherではSQL型が次のようなグループに分類されています。各グループに対応するJPublisherオプションは、各項に示したとおりです。
数値型: SQL型NUMBER
として格納されるすべての型
ラージ・オブジェクト(LOB)型: SQL型のBLOB
およびCLOB
組込み型: データベース内にSQL型として格納されている型のうち、前に示した分類のどれにも該当しない型(たとえば、CHAR
、VARCHAR2
、LONG
、RAW
など)
JPublisherでは次の型マッピング・モードを定義します。
JDBCマッピング(設定はjdbc
): SQL型とネイティブなJava型とのマッピングに標準デフォルト・マッピング型を使用します。この設定は、-numbertypes
、-lobtypes
および-builtintypes
オプションに有効です。
Oracleマッピング(設定はoracle
): SQL型へのマッピングの際に、対応するoracle.sql
型を使用します。この設定は、-numbertypes
、-lobtypes
および-builtintypes
オプションに有効です。
Object JDBCマッピング(設定はobjectjdbc
): JDBCマッピングをさらに拡張したマッピングです。オブジェクトJDBCマッピングでは、適切であれば、Javaプリミティブ型(int
、float
、double
など)のかわりに、標準java.lang
パッケージの数値オブジェクト型(java.lang.Integer
、Float
、Double
など)が使用されます。java.lang
型ではNULL値が許容されますが、基本型では許容されません。この設定は、-numbertypes
オプションにのみ有効です。
BigDecimal
マッピング(設定はbigdecimal
): 数値属性へのマッピングの際にjava.math.BigDecimal
を使用します。これは、桁数の多い数値を使用してもoracle.sql.NUMBER
型は使用しない場合に適したマッピング方法です。この設定は、-numbertypes
オプションにのみ有効です。
注意: BigDecimal マッピングを使用すると、パフォーマンスが著しく劣化する場合があります。 |
SQLオブジェクト型や要素型の属性型に対してマッピング指定を省略すると、JPublisherでは次のデフォルトが使用されます。
数値型のデフォルトは、Object JDBCマッピングです。
LOB型のデフォルトは、Oracleマッピングです。
組込みタイプ型のデフォルトは、JDBCマッピングです。
これ以外に代替のマッピングを使用する場合は、-numbertypes
、-lobtypes
および-builtintypes
オプションを使用します。どのオプションを使用するかは、処理対象とする属性型およびマッピングに応じて決めてください。
属性型自体がSQLオブジェクト型である場合には、-usertypes
設定値に基づいてマッピングされます。
注意: カスタム・オブジェクト・クラスに対してSQLData が実装されるように指定し、コードが移植可能であるようにする場合は、属性型に対して移植可能なマッピングを使用する必要があります。数値型または組込み型をマッピング対象とする場合はデフォルトで移植可能になりますが、LOB型の場合は-lobtypes=jdbc を指定する必要があります。 |
表6-1に、SQL型、マッピング設定およびデフォルト設定に関してJPublisherでの分類をカテゴリ別にまとめます。
表6-1 JPublisherでのSQL型の分類、サポートされている設定およびデフォルト
SQL型の分類 | JPublisherマッピング・オプション | マッピング設定 | デフォルト |
---|---|---|---|
UDT型 |
|
|
|
数値型 |
|
|
|
LOB型 |
|
|
|
組込み型 |
|
|
|
注意: 以前のリリースで使用された-mapping オプションは、JPublisherでは非推奨ですが、サポートはされています。JPublisherの-mapping オプション設定値を新しいマッピング・オプション設定値に変換する方法の詳細は、『Oracle Database JPublisherユーザーズ・ガイド』を参照してください。 |
OracleオブジェクトをJavaにマッピングするためのカスタム・オブジェクト・クラスを作成する際、-methods
オプションは、OracleオブジェクトのメソッドにJavaラッパーを含めるかどうかをJPublisherに指示します。デフォルトの-methods=true
設定では、ラッパーが生成され、JPublisherではカスタム・オブジェクト・クラス用に.java
ファイルではなく.sqlj
ファイルが生成されます(ただし、基になるSQLオブジェクトに実際にメソッドない場合を除きます)。
JPublisherでラッパー・メソッドを生成すると、元のオブジェクト・メソッドがstaticでも、必ずインスタンス・メソッドになります。次に、-methods
オプションの設定例を示します。
% jpub -sql=Myobj,mycoll:MyCollClass -user=scott -methods=true
Enter scott password: password
この例では、デフォルトのネーミング・メソッドが使用されます。Javaのメソッド名は、最初の文字が小文字になる他は、カスタムJavaクラス名と同じ方法でネーミングされます。たとえば、オブジェクトのメソッド名CALC_SAL
は、デフォルトでJavaのラッパー・メソッド名calcSal()
になります。かわりにJavaのメソッド名を指定することも可能ですが、この場合は、JPublisherのINPUT
ファイルを使用する必要があります。
注意: -methods オプションには他の用途もあり、例としては、パッケージのラッパー・クラスやパッケージのメソッドのラッパー・メソッドの生成に使用できます。この内容はこのマニュアルの対象外です。詳細は、『Oracle Database JPublisherユーザーズ・ガイド』を参照してください。 |
オーバーロード・メソッドについて
JPublisherの実行対象のOracleオブジェクトにオーバーロード・メソッドがあり、複数のシグネチャが同一のJavaシグネチャに対応する場合は、シグネチャごとに一意なメソッド名が生成されます。つまり、ファンクション名の後ろに_n
が付けられます(n
は番号です)。生成されたカスタムJavaクラスの2つのメソッドは、それぞれ一意な名前とシグネチャになります。一例として、MY_TYPE
オブジェクト型の生成時に定義されるSQLファンクションについて考えます。
CREATE OR REPLACE TYPE my_type AS OBJECT ( ... MEMBER FUNCTION myfunc(x INTEGER) RETURN my_return IS BEGIN ... END; MEMBER FUNCTION myfunc(y SMALLINT) RETURN my_return IS BEGIN ... END; ... );
このままでは、myfunc
の定義は両方とも、Java形式の名前とシグネチャになります。
myfunc(Integer)
その理由は、SQL形式のINTEGER
およびSMALLINT
が、Java Integer
型にマッピングされているためです。
かわりに、JPublisherでは、myfunc_1
ともう1つのmyfunc_2
をコールします。_n
はそれぞれ一意です。簡単な例では、_1
、_2
のようになりますが、各ファンクションに一意の値ではなく、任意の値でもかまいません。
注意: オーバーロードしたラッパー・メソッドに対するJPublisherでの処理は、オブジェクトやパッケージ内で作成されたSQLファンクションに対しても実行されます。最上位レベルではオーバーロードが許容されません。 |
JPublisherでは、カスタムJavaクラスを生成できる他、オブジェクト型またはコレクション型のマッピング先として、生成したクラスでなく代替クラスが指定できます。
通常は、JPublisherで生成したクラスをスーパークラスにし、これを拡張して機能を追加し、オブジェクト型をサブクラスにマッピングします。たとえば、Oracleオブジェクト型ADDRESS
のカスタムJavaクラスを作成し、JPublisherで生成されなかった機能を追加するとします。この場合は、JPublisherでJAddress
カスタムJavaクラスを生成してから、これを拡張してMyAddress
クラスを作成します。専用機能をMyAddressに追加してから、JPublisherでADDRESS
オブジェクトを、JAddress
クラスではなく、MyAddress
にマッピングします。JPublisherでは、JAddress
ではなく、MyAddress
の参照クラスも生成できます。
JPublisherでは、代替クラスへのマッピングを容易に行えます。-sql
オプションを次の構文で指定します。
-sql=object_type:generated_class:map_class
前の例の場合は、次のように設定します。
-sql=ADDRESS:JAddress:MyAddress
この設定では、クラスJAddress
がソース・ファイルJAddress.sqlj
(またはJAddress.java
)に作成され、次の処理が行われます。
ADDRESS
オブジェクト型のマッピング先が、JAddress
クラスではなく、MyAddress
クラスになります。したがって、データベースから取得したオブジェクトにADDRESS
属性があると、Javaでこの属性がMyAddress
のインスタンスとして生成されます。ADDRESS
オブジェクトを直接取得する場合は、MyAddress
インスタンスに取り込まれます。
JAddressRef
クラスではなく、MyAddressRef
クラスがMyAddressRef.java
に生成されます。
ファイルがすでに存在していないかぎり、MyAddress.sqlj
(またはMyAddress.java
)ソース・ファイルにMyAddress
クラスの初期バージョンが生成されます。存在している場合、ファイルは変更されません。
MyAddress
はJAddress
にサブクラス化されます。MyAddress
に対して拡張機能を実装するためには、JPublisherで生成されたMyAddress
ソース・ファイルを使用し、必要に応じてそのファイルを編集できます。
JPublisher生成クラスを拡張する方法(前例の続き)は、「JPublisher生成クラスの拡張」を参照してください。
JPublisherでは、専用のINPUT
ファイルおよび標準のプロパティ・ファイルを使用して、型のマッピングなどのオプション設定を指定できます。
JPublisherのコマンドライン・オプション-input
を使用して、型マッピングを追加するためのINPUT
ファイルをJPublisherに指定できます。INPUT
ファイル内のSQL
は、コマンドラインの-sql
に相当し、AS
またはGENERATE...AS
構文は、コマンドラインのコロン区切り構文に相当します。次の構文を使用しますが、1つのSQLコマンドに指定できるマッピングは1つだけです。
SQL udt1 <GENERATE GeneratedClass1> <AS MapClass1> SQL udt2 <GENERATE GeneratedClass2> <AS MapClass2> ...
GeneratedClass1
とGeneratedClass2
が生成され、udt1
がMapClass1
に、udt2
がMapClass2
にマッピングされます。
INPUTファイルの例
次の例では、JPublisherは、コマンドラインの-user
オプションに基づき、INPUT
ファイルmyinput.in
で型マッピングを調べます。
コマンドラインで次のように指定します。
% jpub -input=myinput.in -user=scott
Enter scott password: password
INPUT
ファイルmyinput.in
の内容は次のようになります。
SQL Myobj SQL mycoll AS MyCollClass SQL employee GENERATE Employee AS MyEmployee
次の処理が行われます。
ユーザー定義型MYOBJ
の名前は、カスタム・オブジェクト・クラスの名前として入力したMyobj
になります。JPublisherでは、ソース・ファイルMyobj.sqlj
(またはMyobj
にメソッドがない場合はMyobj.java
)およびMyobjRef.java
が作成されます。
ユーザー定義型MYCOLL
が、MyCollClass
にマッピングされます。JPublisherでは、MyCollClass.java
ソース・ファイルが生成されます。
ユーザー定義型EMPLOYEE
がMyEmployee
クラスにマッピングされます。JPublisherでは、ファイルがすでに存在していないかぎり、初期バージョンのMyEmployee.sqlj
(または.java
)に加え、ソース・ファイルEmployee.sqlj
(またはEmployee.java
)およびMyEmployeeRef.java
が作成されます。データベースから取得したオブジェクトにEMPLOYEE
属性があると、Javaでこの属性がMyEmployee
のインスタンスとして生成されます。EMPLOYEE
オブジェクトを直接取得する場合は、MyEmployee
のインスタンスに取り込まれます。MyEmployee
コードに関する責任は開発者にありますが、EMPLOYEE
オブジェクトに対して特別な機能をJavaで実装するためには、JPublisherで生成したMyEmployee
ソース・ファイルを利用して、そのファイルを編集できます。MyEmployee
はEmployee
クラスにサブクラス化されます。
JPublisherのコマンドライン・オプション-props
で、型マッピングなどのオプション設定に使用するプロパティ・ファイルを指定できます。
プロパティ・ファイルでのjpub.
(ピリオドを含む)は、コマンドラインの-
(シングル・ダッシュ)に相当します。その他の構文は同じです。1行に1つのオプションを指定してください。
型マッピングの場合、jpub.sql
は-sql
に相当します。単一のjpub.sql
設定で複数のマッピングを指定できます。また、複数のjpub.sql
オプションを使用できます。複数の-sql
オプションが1つのコマンドラインにある場合、オプションの効果は累積されます。
注意: jpub. または--jpub. (2つのダッシュの後にjpub. が続く)で開始しないプロパティ・ファイルの行は無視されます。これによって、型を作成するSQLスクリプトとJPublisher用のプロパティ・ファイルに同じファイルを使用できます。JPublisherの各文を「-- 」(SQLのコメントを示す)で開始すると、SQL*Plusでは無視されます。また、SQL文はJPublisherによって無視されます。 |
プロパティ・ファイルの例
次の例では、JPublisherはコマンドラインの-user
オプションに基づき、プロパティ・ファイルjpub.properties
で型マッピングと属性マッピング・オプションを調べます。
コマンドラインで次のように指定します。
% jpub -props=jpub.properties -user=scott
Enter scott password: password
プロパティ・ファイルjpub.properties
の内容は次のとおりです。
jpub.sql=Myobj,mycoll:MyCollClass,employee:Employee:MyEmployee jpub.usertypes=oracle
このように指定すると、oracle
マッピングの設定が明示的に指定され、前の入力ファイルの例と同じ結果になります。
注意: SQLJと異なり、JPublisherにはデフォルトのプロパティ・ファイルがありません。プロパティ・ファイルを使用するには、-props オプションを使用します。 |
カスタムJavaクラスの作成時に、カスタム・クラスの属性またはメソッドの名前を指定できます。ただし、この属性やメソッド名は、JPublisherコマンドラインでの指定はできません。次のようにTRANSLATE
構文を使用して、JPublisherのINPUT
ファイルで指定する必要があります。
SQL udt <GENERATE GeneratedClass> <AS MapClass> <TRANSLATE membername1 AS Javaname1> <, membername2 AS Javaname2> ...
TRANSLATE
ペア(membernameN
AS
JavanameN
)はカンマで区切ります。
たとえば、EMPLOYEE
Oracleオブジェクト型のADDRESS
属性の名前をHomeAddress
にし、GIVE_RAISE
メソッドの名前をgiveRaise()
にするとします。また、Employee
クラスを作成し、EMPLOYEE
オブジェクトのマッピング先をこれから作成するMyEmployee
クラスにするとします。(この例はINPUT
ファイル構文の全体を示すものであり、メンバー名の指定には関係ありません。)
SQL employee GENERATE Employee AS MyEmployee TRANSLATE address AS HomeAddress, GIVE_RAISE AS giveRaise
注意:
|
ここでは、JPublisherでのラッパー・メソッドの生成方法と、ランタイムのラッパー・メソッド・コールの処理方法を説明します。
ラッパー・メソッドの生成
次に、JPublisherでのラッパー・メソッドの生成方法について説明します。
JPublisherで生成したラッパー・メソッドは、SQLJで実装されます。したがって、-methods=true
に設定すると、オブジェクト型でメソッドを定義している場合は、カスタム・オブジェクト・クラスが、.java
ファイルではなく、.sqlj
ファイルに定義されます。.sqlj
ファイルを変換するには、SQLJを実行します。
注意: オブジェクト型でメソッドを定義していない場合でも、-methods=always の設定で.sqlj ファイルが生成されることを確認できます。詳細は、『Oracle Database JPublisherユーザーズ・ガイド』を参照してください。 |
JPublisherで生成したラッパー・メソッドは、すべてインスタンス・メソッドとして実装されます。サーバー側メソッドの起動にデータベース接続を必要とするからです。JPublisher生成のカスタムJavaクラスの各インスタンスに接続が対応付けられます。
ラッパー・メソッド・コールのランタイム実行
JPublisherで生成したJavaラッパー・メソッドをランタイムに実行する方法を説明します。ここで取り上げるJavaラッパー・メソッドとは、カスタムJavaオブジェクトのメソッドのことを指していますが、SQLメソッドのラッピングとは、SQLオブジェクトのメソッドをラッパー・メソッドでラッピングすることを指します。
カスタムJavaオブジェクトがSQLオブジェクトに変換され、データベースに渡されると、ラッピングされたSQLメソッドが起動されます。このSQLメソッドの起動後、SQLオブジェクトの新しい値が戻り値として新規のカスタムJavaオブジェクトの形でJavaに戻されます。この戻り値は、ラッピングされたSQLメソッドからのファンクション戻り値(SQLメソッドがストアド・プロシージャの場合)、または追加の出力パラメータの配列要素(SQLメソッドがストアド・ファンクションで、ファンクション戻り値がすでに存在している場合)のどちらかになります。
出力または入出力パラメータが単一要素配列の要素として渡されます。入出力パラメータの場合は、ラッパー・メソッドが入力として配列要素をとります。処理後、ラッパーによって出力が配列要素に代入されます。
ここでは、次のユーザー定義型に対して、JPublisherで生成されるORAData
実装の例を示します。
カスタム・オブジェクト・クラス(Oracleのオブジェクト型 ADDRESS
に対応するAddress
)とそのカスタム参照クラス(AddressRef
)
カスタム・コレクション・クラス(Oracleのコレクション型MODULETBL_T
に対応するMODULETBL_T
)
-methods
オプションがデフォルトのtrue
に設定されており、ADDRESS
型にメソッドがあるとします。この結果、.sqlj
ファイルがAddress
クラスに対して生成されます。
関連項目: JPublisherで生成されるSQLDataおよびORAData実装の各例については、 『Oracle Database JPublisherユーザーズ・ガイド』 を参照してください。 |
カスタム・オブジェクト・クラス: Address.sqlj
次に、JPublisherで生成されるカスタム・オブジェクト・クラスのソース・コードの例を示します。実装の詳細は省略されています。
この例では、「オブジェクト型の作成」と異なり、OracleオブジェクトADDRESS
の属性はstreet
とzip_code
のみです。
package bar; import java.sql.SQLException; import java.sql.Connection; import oracle.jdbc.OracleTypes; import oracle.sql.ORAData; import oracle.sql.ORADataFactory; import oracle.sql.Datum; import oracle.sql.STRUCT; import oracle.jpub.MutableStruct; public class Address implements ORAData, ORADataFactory { public static final String _SQL_NAME = "SCOTT.ADDRESS"; public static final int _SQL_TYPECODE = OracleTypes.STRUCT; public static ORADataFactory getORADataFactory() { ... } /* constructors */ public Address() { ... } public Address(String street, java.math.BigDecimal zip_code) throws SQLException { ... } /* ORAData interface */ public Datum toDatum(Connection c) throws SQLException { ... } /* ORADataFactory interface */ public ORAData create(Datum d, int sqlType) throws SQLException { ... } /* accessor methods */ public String getStreet() throws SQLException { ... } public void setStreet(String street) throws SQLException { ... } public java.math.BigDecimal getZipCode() throws SQLException { ... } public void setZipCode(java.math.BigDecimal zip_code) throws SQLException { ... } }
カスタム参照クラス: AddressRef.java
次に、ADDRESS
オブジェクトへの参照としてJPublisherで生成されるカスタム参照クラスのソース・コードの例を示します。実装の詳細は省略されています。
package bar; import java.sql.SQLException; import java.sql.Connection; import oracle.jdbc.OracleTypes; import oracle.sql.ORAData; import oracle.sql.ORADataFactory; import oracle.sql.Datum; import oracle.sql.REF; import oracle.sql.STRUCT; public class AddressRef implements ORAData, ORADataFactory { public static final String _SQL_BASETYPE = "SCOTT.ADDRESS"; public static final int _SQL_TYPECODE = OracleTypes.REF; public static ORADataFactory getORADataFactory() { ... } /* constructors */ public AddressRef() { ... } public static AddressRef(ORAData o) throws SQLException { ... } /* ORAData interface */ public Datum toDatum(Connection c) throws SQLException { ... } /* ORADataFactory interface */ public ORAData create(Datum d, int sqlType) throws SQLException { ... } public static AddressRef cast(ORAData o) throws SQLException { ... } public Address getValue() throws SQLException { ... } public void setValue(Address c) throws SQLException { ... } }
カスタム・コレクション・クラス: ModuletblT.java
次に、JPublisherで生成されるカスタム・コレクション・クラスのソース・コードの例を示します。実装の詳細は省略されています。
import java.sql.SQLException; import java.sql.Connection; import oracle.jdbc.OracleTypes; import oracle.sql.ORAData; import oracle.sql.ORADataFactory; import oracle.sql.Datum; import oracle.sql.ARRAY; import oracle.sql.ArrayDescriptor; import oracle.jpub.runtime.MutableArray; public class ModuletblT implements ORAData, ORADataFactory { public static final String _SQL_NAME = "SCOTT.MODULETBL_T"; public static final int _SQL_TYPECODE = OracleTypes.ARRAY; public static ORADataFactory getORADataFactory() { ... } /* constructors */ public ModuletblT() { ... } public ModuletblT(ModuleT[] a) { ... } /* ORAData interface */ public Datum toDatum(Connection c) throws SQLException { ... } /* ORADataFactory interface */ public ORAData create(Datum d, int sqlType) throws SQLException { ... } public String getBaseTypeName() throws SQLException { ... } public int getBaseType() throws SQLException { ... } public ArrayDescriptor getDescriptor() throws SQLException { ... } /* array accessor methods */ public ModuleT[] getArray() throws SQLException { ... } public void setArray(ModuleT[] a) throws SQLException { ... } public ModuleT[] getArray(long index, int count) throws SQLException { ... } public void setArray(ModuleT[] a, long index) throws SQLException { ... } public ModuleT getObjectElement(long index) throws SQLException { ... } public void setElement(ModuleT a, long index) throws SQLException { ... } }
JPublisherで生成したカスタムJavaクラスは、メソッドと一時フィールドを追加して、機能を拡張できます。このためには、JPublisher生成クラスを拡張します。
たとえば、JPublisherで、ADDRESS
SQLのオブジェクト型からJAddress
クラスを生成するとします。また、ADDRESS
オブジェクトを表すMyAddress
クラスを使用し、特別な機能を実装します。このMyAddress
クラスは、JAddress
の拡張クラスとする必要があります。
JPublisher生成クラスの機能を拡張する場合は、単にメソッドを追加する方法もあります。ただし、クラスをJPublisherで再生成する予定がある場合は、JPublisher生成クラスへのメソッドの追加は避けてください。この方法で変更したクラスをJPublisherで再生成する場合は、コピーを保存しておき、変更内容を手動でマージする必要があります。
生成クラスを拡張するためのJPublisherの機能
次のJPublisherの構文でJAddress
を生成し、MyAddress
にマッピングできます。
-sql=ADDRESS:JAddress:MyAddress
または、INPUT
ファイルで次のように指定します。
SQL ADDRESS GENERATE JAddress AS MyAddress
このように指定した結果、JPublisherで生成される参照クラスは、MyAddressRef.java
のMyAddressRef
であって、JAddressRef
が生成されることはありません。
また、JPublisher生成コードが変更され、次の機能が実装されます。
SQL型ADDRESS
の属性は、JAddress
クラスではなく、MyAddress
クラスで表されます。
ADDRESS
型のメソッド引数およびファンクション結果は、JAddress
クラスではなく、MyAddress
クラスで表されます。
SQL型ADDRESS
のJavaオブジェクトは、JAddress
ファクトリではなく、MyAddress
ファクトリで構築されます。
追加コードを作成する場合も、おそらくMyAddress
を使用することになります。
実行時にOracle JDBCドライバによって、データベース内のADDRESS
データのオカレンスが、JAddress
のインスタンスではなく、MyAddress
のインスタンスにマッピングされます。
拡張クラスの要件
JPublisherではデフォルトの場合、作成されるファイルがすでに存在していないかぎり、MyAddress.sqlj
ファイル(元のクラスがメソッドを使用し、これらのメソッドを公開している場合)またはMyAddress.java
ファイルに、初期バージョンのMyAddress
ユーザー・サブクラスが作成されます(ファイルがすでに存在している場合、ファイルは変更されません)。このファイルは、必要な機能を追加するために編集できます。
MyAddress
には、引数を持たないコンストラクタを用意する必要があります。適切に初期化したオブジェクトを容易に構築するには、スーパークラスのコンストラクタを明示的にまたは暗黙的に起動します。
JPublisher生成クラスを拡張した場合、_SQL_NAME
フィールド(必須)の定義と_SQL_TYPECODE
フィールドの定義がサブクラスに継承されます。
また、次のどちらかが当てはまります。
JPublisherで生成したクラスには、ORAData
およびORADataFactory
インタフェースが実装されているため、必要とされるtoDatum()
およびJPublisherで生成されたクラスのcreate()
機能がサブクラスに継承されます。ただし、サブクラスには、自分でマッピングしたクラスのインスタンス(MyAddress
オブジェクトなど)を戻り値とするgetORADataFactory()
メソッドを実装します。
JPublisherで生成したクラスにSQLData
インタフェースが実装されている場合、この実装と生成クラスのreadSQL()
およびwriteSQL()
機能とがサブクラスに継承されます。
JPublisher生成のカスタム・オブジェクト・クラス: JAddress.sqlj
JPublisherで生成されたJAddress
クラスのコード(ORAData
およびORADataFactory
を実装する)は、Address
がJAddress
に置換されることを除き、前述のAddress
クラスのコードとほぼ同じです。
JPublisher生成のその他の参照クラス: MyAddressRef.java
これまでの項の例の続きとして、JPublisher生成の参照クラスMyAddressRef
のコードを検討します(MyAddress
クラスがADDRESS
オブジェクトのマッピング先となるため、ここで取り上げるクラスはJAddressRef
ではありません)。また、このクラスにはORAData
とORADataFactory
も実装されます。この実装は、クラス名が異なることと、アクセッサ・メソッドがAddress
インスタンスではなくMyAddress
インスタンスを使用することを除いて、AddressRef.java
の実装とほぼ同じです。
拡張カスタム・オブジェクト・クラス: MyAddress.sqlj
これまでの例の続きとして、JPublisherで生成されるJAddress
クラスのサブクラスであるMyAddress
のサンプル・コードを示します。JAddress
から継承された内容は、コード中のコメントに記述してあります。実装の詳細は省略されています。
import java.sql.SQLException; import oracle.sql.ORAData; import oracle.sql.ORADataFactory; import oracle.sql.Datum; import oracle.sql.STRUCT; import oracle.jpub.runtime.MutableStruct; public class MyAddress extends JAddress { /* _SQL_NAME inherited from MyAddress */ /* _SQL_TYPECODE inherited from MyAddress */ static _myAddressFactory = new MyAddress(); public static ORADataFactory getORADataFactory() { return _myAddressFactory; } /* constructor */ public MyAddress() { super(); } /* ORAData interface */ /* toDatum() inherited from JAddress */ /* ORADataFactory interface */ public ORAData create(oracle.sql.Datum d, int sqlType) throws SQLException { ... } /* accessor methods inherited from JAddress */ /* Additional methods go here. These additional methods (not shown) are the reason that JAddress was extended. */ }
Oracle SQLJ実装では、強い型指定のオブジェクトまたは参照をホスト式およびイテレータで使用して、オブジェクト・データの読込みおよび書込みを柔軟に行えます。
イテレータの場合は、カスタム・オブジェクト・クラスをイテレータの列型として使用できます。または、属性のSQLデータ型にマップしている列型を使用して、イテレータ列をオブジェクトの各属性に対応付けることができます(エクステント表と同様)。
ホスト式の場合は、カスタム・オブジェクト・クラス型またはカスタム参照クラス型のホスト変数を使用できます。または、属性のSQLデータ型にマップしている変数型を使用して、ホスト変数をオブジェクトの属性に対応付けることができます。
次に、Oracleオブジェクトの操作例を示します。SQLJ実行文のホスト変数とイテレータ列に対して、カスタム・オブジェクト・クラス、カスタム・オブジェクト・クラスの属性およびカスタム参照クラスを使用します。
次の2つの例は、オブジェクト・レベルでの操作です。
「各オブジェクト属性から作成したオブジェクトの挿入」の例は、スカラー属性レベルでの操作です。
「オブジェクト参照の更新」の例は、参照による操作です。
Oracleのオブジェクト型ADDRESS
およびPERSON
は、「オブジェクト型の作成」を参照してください。
この例では、カスタムJavaクラスとカスタム参照クラスをイテレータの列型として使用します。ADDRESS
Oracleオブジェクト型が次のように定義されているものとします。
CREATE TYPE ADDRESS AS OBJECT ( street VARCHAR(40), zip NUMBER );
また、EMPADDRS
表が次のように定義されているものとします。この表には、ADDRESS
列とADDRESS
参照列があります。
CREATE TABLE empaddrs ( name VARCHAR(60), home ADDRESS, loc REF ADDRESS );
ADDRESS
Oracleオブジェクト型に対応するカスタムJavaクラスAddress
とカスタム参照クラスAddressRef
をJPublisherで生成するか、または手動で作成すると、次のようにAddress
とAddressRef
とを名前付きイテレータで使用できます。
#sql iterator EmpIter (String name, Address home, AddressRef loc); ... EmpIter ecur; #sql ecur = { SELECT name, home, loc FROM empaddrs }; while (ecur.next()) { Address homeAddr = ecur.home(); // Print out the home address. System.out.println ("Name: " + ecur.name() + "\n" + "Home address: " + homeAddr.getStreet() + " " + homeAddr.getZip()); // Now update the loc address zip code through the address reference. AddressRef homeRef = ecur.loc(); Address location = homeRef.getValue(); location.setZip(new BigDecimal(98765)); homeRef.setValue(location); } ...
ecur.home()
メソッド・コールは、イテレータのhome
列からAddress
オブジェクトを抽出し、homeAddr
ローカル変数に代入します(効率化)。このオブジェクトの属性にアクセスするには、次に示したJavaの標準ドット区切り構文を使用します。
homeAddr.getStreet()
ロケーション・アドレス(この例ではzipコード)を操作するには、getValue()
およびsetValue()
メソッドを使用します。これらのメソッドは、JPublisher生成のカスタム参照クラスの標準機能です。
この例では、Address
Java型の入力ホスト変数を宣言し、設定することで、employees
表の列にあるADDRESS
オブジェクトを更新します。更新前と更新後の両方で、アドレスが選択されてAddress
型の出力ホスト変数に入力され、検証用に出力されます。
... // Updating an object static void updateObject() { Address addr; Address new_addr; int empnum = 1001; try { #sql { SELECT office_addr INTO :addr FROM employees WHERE empnumber = :empnum }; System.out.println("Current office address of employee 1001:"); printAddressDetails(addr); /* Now update the street of address */ String street ="100 Oracle Parkway"; addr.setStreet(street); /* Put updated object back into the database */ try { #sql { UPDATE employees SET office_addr = :addr WHERE empnumber = :empnum }; System.out.println ("Updated employee 1001 to new address at Oracle Parkway."); /* Select new address to verify update */ try { #sql { SELECT office_addr INTO :new_addr FROM employees WHERE empnumber = :empnum }; System.out.println("New office address of employee 1001:"); printAddressDetails(new_addr); } catch (SQLException exn) { System.out.println("Verification SELECT failed with "+exn); } } catch (SQLException exn) { System.out.println("UPDATE failed with "+exn); } } catch (SQLException exn) { System.out.println("SELECT failed with "+exn); } } ...
Address
オブジェクトのsetStreet()
アクセッサ・メソッドが使用されています。JPublisherで生成したカスタムJavaクラスには、属性ごとにアクセッサ・メソッドが用意されています。
この例では、printAddressDetails()
ユーティリティを使用しています。このメソッドのソース・コードを次に示します。
static void printAddressDetails(Address a) throws SQLException { if (a == null) { System.out.println("No Address available."); return; } String street = ((a.getStreet()==null) ? "NULL street" : a.getStreet()) ; String city = (a.getCity()==null) ? "NULL city" : a.getCity(); String state = (a.getState()==null) ? "NULL state" : a.getState(); String zip_code = (a.getZipCode()==null) ? "NULL zip" : a.getZipCode(); System.out.println("Street: '" + street + "'"); System.out.println("City: '" + city + "'"); System.out.println("State: '" + state + "'"); System.out.println("Zip: '" + zip_code + "'" ); }
この例では、PERSON
オブジェクトとネストされているADDRESS
オブジェクトの属性に対応する入力ホスト変数を宣言し、設定します。これらの値を使用して、新しいPERSON
オブジェクトをデータベース内のpersons
表に挿入します。
... // Inserting an object static void insertObject() { String new_name = "NEW PERSON"; int new_ssn = 987654; String new_street = "NEW STREET"; String new_city = "NEW CITY"; String new_state = "NS"; String new_zip = "NZIP"; /* * Insert a new PERSON object into the persons table */ try { #sql { INSERT INTO persons VALUES (PERSON(:new_name, :new_ssn, ADDRESS(:new_street, :new_city, :new_state, :new_zip))) }; System.out.println("Inserted PERSON object NEW PERSON."); } catch (SQLException exn) { System.out.println("INSERT failed with "+exn); } } ...
この例では、persons
表からPERSON
参照を選択し、この値を使用してemployees
表内のPERSON
参照を更新します。属性値の基準チェックには、単純な入力ホスト変数を使用します。新しく更新された参照を使用して、その参照先のPERSON
オブジェクトを選択することで、情報を出力して、ユーザーが変更内容を検証できるようになります。
... // Updating a REF to an object static void updateRef() { int empnum = 1001; String new_manager = "NEW PERSON"; System.out.println("Updating manager REF."); try { #sql { UPDATE employees SET manager = (SELECT REF(p) FROM persons p WHERE p.name = :new_manager) WHERE empnumber = :empnum }; System.out.println("Updated manager of employee 1001. Selecting back"); } catch (SQLException exn) { System.out.println("UPDATE REF failed with "+exn); } /* Select manager back to verify the update */ Person manager; try { #sql { SELECT deref(manager) INTO :manager FROM employees e WHERE empnumber = :empnum }; System.out.println("Current manager of "+empnum+":"); printPersonDetails(manager); } catch (SQLException exn) { System.out.println("SELECT REF failed with "+exn); } } ...
注意: この例では、前述の表の別名構文(p )を使用しています。また、参照先オブジェクトから参照を選択するには、REF 構文が必要になり、参照からオブジェクトを選択するには、DEREF 構文が必要になります。表の別名、REF およびDEREF の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。 |
Oracle SQLJ実装では、強い型指定のオブジェクトおよび参照と同じように、強い型指定のコレクションをイテレータまたはホスト式で使用して、データの読込みおよび書込みを行えます。
SQLJ開発者にとっては、2種類のコレクション(VARRAYとネストした表)の扱いは基本的に同じですが、実装とパフォーマンスの面で相違点が多少あります。
Oracle SQLJ実装では、構文の複数の選択肢がサポートされていて、ネストした表(内側の表)にアクセスして、操作できるようになっています(外側の表から切り離して、または外側の表と一緒に操作することも可能です)。ここでは、ネストの内側の表のみの操作を詳細レベルの操作と呼び、ネストの内側の表と外側の表の同時操作をマスター・レベルの操作と呼びます。
ここでは、いくつかの構文について簡単に説明してから、ネストした表の操作例を示します。ネストした表の操作は、VARRAYの操作より複雑です。
MODULETBL_T
Oracleコレクション型と関連する表、およびオブジェクト型の定義については、「コレクション型の作成」を参照してください。
注意: Oracle SQLJ実装では、VARRAY型およびNESTED TABLE型を型単位でのみ取得できます。これは、Oracle SQL実装とは違い、ネストした表の問合せを選択的に実行できます。 |
ここでは、次の項目について説明します。
Oracle SQLJ実装では、ネストしたイテレータを使用して、ネストした表のデータにアクセスできます。外部のSELECT
文でCURSOR
キーワードを使用し、内部のSELECT
文をカプセル化します。「ネスト・イテレータによるネストした表からのデータの選択」を参照してください。
Oracleでは、TABLE
キーワードを使用すると、ネストした表を行単位で操作できます。Oracleではこのキーワードを使用すると、副問合せで戻される列値が、スカラー値ではなくネストした表であることが認識されます。単一列値を戻す副問合せまたはネストした表に解決される式の前に、TABLE
キーワードを指定する必要があります。
次に、TABLE
構文の使用例を示します。
UPDATE TABLE(SELECT a.modules FROM projects a WHERE a.id=555) b SET module_owner= (SELECT ref(p) FROM employees p WHERE p.ename= 'Smith') WHERE b.module_name = 'Zebra';
この例のTABLE
を見ると、ネストの外側の表の列から選択された、ネストの内側の単一の表を参照していることがわかります。
注意: この例では、前述のように、表の別名構文(projects にはa 、ネストした表にはb 、またemployees にはp )が使用されています。 |
この例では、マスター・レベル(ネストの外側の表)と詳細レベル(ネストの内側の表)を同時に明示的に操作する処理を示します。ここでは、projects
表に行を挿入します。この表の各行にはMODULETBL_T
型のネストした表が含まれ、ネストした表にはMODULE_T
オブジェクトの行が含まれています。
最初に、スカラー値を設定し(id
、name
、start_date
、duration
)、ネストした表の値を設定します。ネストした表の要素は複数の属性を持つオブジェクトであるため、別のレベルの抽象化も行いますネストした表の値を設定するとき、ネストした表の各MODULE_T
オブジェクトに対して、各属性値を設定する必要があります。最後に、owner
値(初期値null
)を別の文で設定します。
// Insert Nested table details along with master details public static void insertProject2(int id) throws Exception { System.out.println("Inserting Project with Nested Table details.."); try { #sql { INSERT INTO Projects(id,name,owner,start_date,duration, modules) VALUES ( 600, 'Ruby', null, '10-MAY-98', 300, moduletbl_t(module_t(6001, 'Setup ', null, '01-JAN-98', 100), module_t(6002, 'BenchMark', null, '05-FEB-98',20) , module_t(6003, 'Purchase', null, '15-MAR-98', 50), module_t(6004, 'Install', null, '15-MAR-98',44), module_t(6005, 'Launch', null,'12-MAY-98',34))) }; } catch ( Exception e) { System.out.println("Error:insertProject2"); e.printStackTrace(); } // Assign project owner to this project try { #sql { UPDATE Projects pr SET owner=(SELECT ref(pa) FROM participants pa WHERE pa.empno = 7698) WHERE pr.id=600 }; } catch ( Exception e) { System.out.println("Error:insertProject2:update"); e.printStackTrace(); } }
この例では、ネストした表を詳細レベルで直接操作します。前述のとおり、ModuletblT
は、ネストした表MODULETBL_T
に対するJPublisher生成のカスタム・コレクション・クラス(ORAData
実装)であり、ModuleT
はMODULE_T
オブジェクトに対するJPublisher生成のカスタム・オブジェクト・クラスです。ネストした表MODULETBL_T
にはMODULE_T
オブジェクトが格納されます。
MODULE_T
オブジェクトのネストした表をprojects
表のmodules
列から選択し、ModuletblT
ホスト変数に格納します。
次に、ネストした表を含むModuletblT
変数をあるメソッドに渡し、そのメソッドはgetArray()
メソッドを使用して要素にアクセスします。getArray()メソッドはデータをModuleT[]
配列に書き込みます。JPublisherで生成したカスタム・コレクション・クラスには、必ずgetArray()
メソッドがあります。その後、このModuleT[]
配列の各要素をModuleT
オブジェクトにコピーし、各属性をアクセッサ・メソッド(getModuleName()
など)で取得し、出力します。JPublisherで生成したカスタム・オブジェクト・クラスには、必ずこのようなアクセッサ・メソッドがあります。
static ModuletblT mymodules=null; ... public static void getModules2(int projId) throws Exception { System.out.println("Display modules for project " + projId ); try { #sql {SELECT modules INTO :mymodules FROM projects WHERE id=:projId }; showArray(mymodules); } catch(Exception e) { System.out.println("Error:getModules2"); e.printStackTrace(); } } public static void showArray(ModuletblT a) { try { if ( a == null ) System.out.println( "The array is null" ); else { System.out.println( "printing ModuleTable array object of size " +a.length()); ModuleT[] modules = a.getArray(); for (int i=0;i<modules.length; i++) { ModuleT module = modules[i]; System.out.println("module "+module.getModuleId()+ ", "+module.getModuleName()+ ", "+module.getModuleStartDate()+ ", "+module.getModuleDuration()); } } } catch( Exception e ) { System.out.println("Show Array"); e.printStackTrace(); } }
この例では、TABLE
構文を使用して、ネストした表を詳細レベルで操作します。マスター・レベルの基準に基づき、ネストした表の要素に直接アクセスして更新します。
assignModule()
メソッドを使用すると、PROJECTS
表のMODULES
列からMODULE_T
オブジェクトのネストした表が選択された後、このネストして表の特定の行のMODULE_NAME
が更新されます。同様に、deleteUnownedModules()
メソッドを使用すると、MODULE_T
オブジェクトのネストした表が選択され、その後でこのネストした表で所有者のいないモジュール(MODULE_OWNER
がNULL
のモジュール)が削除されます。
これらのメソッドでは、前述のように表の別名構文を使用します。この例では、ネストした表にm
、participants
表にp
を使用しています。
/* assignModule Illustrates accessing the nested table using the TABLE construct and updating the nested table row */ public static void assignModule(int projId, String moduleName, String modOwner) throws Exception { System.out.println("Update:Assign '"+moduleName+"' to '"+ modOwner+"'"); try { #sql {UPDATE TABLE(SELECT modules FROM projects WHERE id=:projId) m SET m.module_owner= (SELECT ref(p) FROM participants p WHERE p.ename= :modOwner) WHERE m.module_name = :moduleName }; } catch(Exception e) { System.out.println("Error:insertModules"); e.printStackTrace(); } } /* deleteUnownedModules // Demonstrates deletion of the Nested table element */ public static void deleteUnownedModules(int projId) throws Exception { System.out.println("Deleting Unowned Modules for Project " + projId); try { #sql { DELETE TABLE(SELECT modules FROM projects WHERE id=:projId) m WHERE m.module_owner IS NULL }; } catch(Exception e) { System.out.println("Error:deleteUnownedModules"); e.printStackTrace(); } }
SQLJでは、ネストした表にアクセスする1つ方法として、ネストしたイテレータの使用があります。このためには、次の例で使用されているCURSOR
構文が必要です。コードで名前付きイテレータ・クラスModuleIter
を定義し、このクラスをmodules
列の型として、別の名前付きイテレータ・クラスProjIter
で使用します。移入されたProjIter
インスタンスの中の各modules
項目は、ネスト・イテレータとして表されたネストした表です。
CURSOR
構文は、ネストされているSELECT
文の要素であり、ネストされているイテレータを移入します。選択されたデータは、イテレータのアクセッサ・メソッドによってユーザーに出力されます。
この例では、前述のように、表の別名構文を使用します。ここでは、projects
表にはa
を使用し、ネストした表にはb
を使用しています。
... // The Nested Table is accessed using the ModuleIter // The ModuleIter is defined as Named Iterator #sql public static iterator ModuleIter(int moduleId , String moduleName , String moduleOwner); // Get the Project Details using the ProjIter defined as // Named Iterator. Notice the use of ModuleIter: #sql public static iterator ProjIter(int id, String name, String owner, Date start_date, ModuleIter modules); ... public static void listAllProjects() throws SQLException { System.out.println("Listing projects..."); // Instantiate and initialize the iterators ProjIter projs = null; ModuleIter mods = null; #sql projs = {SELECT a.id, a.name, initcap(a.owner.ename) as "owner", a.start_date, CURSOR ( SELECT b.module_id AS "moduleId", b.module_name AS "moduleName", initcap(b.module_owner.ename) AS "moduleOwner" FROM TABLE(a.modules) b) AS "modules" FROM projects a }; // Display Project Details while (projs.next()) { System.out.println( "\n'" + projs.name() + "' Project Id:" + projs.id() + " is owned by " +"'"+ projs.owner() +"'" + " start on " + projs.start_date()); // Notice the modules from the ProjIter are assigned to the module // iterator variable mods = projs.modules(); System.out.println ("Modules in this Project are : "); // Display Module details while(mods.next()) { System.out.println (" "+ mods.moduleId() + " '"+ mods.moduleName() + "' owner is '" + mods.moduleOwner()+"'" ); } // end of modules mods.close(); } // end of projects projs.close(); }
ここでは、VARRAYをホスト式に取り出す例を示します。次のSQL定義を想定します。
CREATE TYPE PHONE_ARRAY IS VARRAY (10) OF varchar2(30) / /*** Create ADDRESS UDT ***/ CREATE TYPE ADDRESS AS OBJECT ( street VARCHAR(60), city VARCHAR(30), state CHAR(2), zip_code CHAR(5) ) / /*** Create PERSON UDT containing an embedded ADDRESS UDT ***/ CREATE TYPE PERSON AS OBJECT ( name VARCHAR(30), ssn NUMBER, addr ADDRESS ) / CREATE TABLE employees ( empnumber INTEGER PRIMARY KEY, person_data REF person, manager REF person, office_addr address, salary NUMBER, phone_nums phone_array ) /
PHONE_ARRAY
SQL型からマッピングするPhoneArray
カスタム・コレクション・クラスを、JPublisherで生成するとします。
次のメソッドでこの表から行を選択し、データをPhoneArray
型のホスト変数に格納します。
private static void selectVarray() throws SQLException { PhoneArray ph; #sql {select phone_nums into :ph from employees where empnumber=2001}; System.out.println( "there are "+ph.length()+" phone numbers in the PhoneArray. They are:"); String [] pharr = ph.getArray(); for (int i=0;i<pharr.length;++i) System.out.println(pharr[i]); }
ここでは、ホスト式からVARRAYにデータを挿入する例を示します。前例と同じSQL定義とカスタム・コレクション・クラス(PhoneArray
)を使用します。
次のメソッドはPhoneArray
インスタンスを定義し、ホスト変数として使用して、データをデータベース内のVARRAYに挿入します。
// creates a varray object of PhoneArray and inserts it into a new row private static void insertVarray() throws SQLException { PhoneArray phForInsert = consUpPhoneArray(); // clean up from previous demo runs #sql {delete from employees where empnumber=2001}; // insert the PhoneArray object #sql {insert into employees (empnumber, phone_nums) values(2001, :phForInsert)}; } private static PhoneArray consUpPhoneArray() { String [] strarr = new String[3]; strarr[0] = "(510) 555.1111"; strarr[1] = "(617) 555.2222"; strarr[2] = "(650) 555.3333"; return new PhoneArray(strarr); }
Javaオブジェクトのインスタンスをデータベースとの間で読み書きする場合、Javaクラスに対応するSQLオブジェクト型を定義して、前述のカスタムJavaクラスのマッピング機構を使用すると、利便性が高まることがあります。これによって、Javaオブジェクトへの完全なSQL問合せが可能になります。
ただし、RAW
またはBLOB
型のデータベース列を使用して、Javaオブジェクトをそのまま格納した後で取り出す場合もあります。このためには、2つの方法があります。
標準でない型マップの拡張機能を使用するか、型コード・フィールドをシリアライズ可能なクラスに追加することによって、シリアライズ可能なJavaクラスをRAW
またはBLOB
列にマップできます。これにより、RAW
またはBLOB
としてシリアライズ可能なクラスのインスタンスを格納できます。
ORAData
機能を使用して、RAW
またはBLOB
列に格納できるインスタンスを持つ、シリアライズ可能なラッパー・クラスを定義できます。
これらの方法で実行するシリアライズは、Oracle SQLJランタイム・ライブラリのみ対象です。
ここでは、次の項目について説明します。
RAW
列またはBLOB
列内に直接Javaクラスのインスタンスを格納する場合は、SQLとJavaのマッピングを指定する非標準要件を満たす必要があります。SQLJ文内では、組込み型のように透過的に、シリアライズ可能なJavaオブジェクトを読み書きできます。
SQLとJavaのマッピングを指定する場合、2つのオプションがあります。
型マップを接続コンテキスト宣言で宣言して、この型マップでマッピングを指定します。
public static final
フィールド_SQL_TYPECODE
を使用して、マッピングを指定します。
シリアライズ可能なクラスに対する型マップの定義
SAddress
、pack.SPerson
およびpack.Manager.InnerSPM
(InnerSPM
はManager
の内部クラスです)がシリアライズ可能なJavaクラスであるとします。つまり、これらのクラスはjava.io.Serializable
インタフェースを実装します。
このクラスは、宣言済の接続コンテキスト型の明示的接続コンテキスト・インスタンスを使用する文でのみ採用する必要があります。次のSerContext
がその例です。
SAddress a =...; pack.SPerson p =...; pack.Manager.InnerSPM pm =...; SerContext ctx = new SerContext(url,user,pwd,false); #sql [ctx] { ... :a ... :OUT p ... :INOUT pm ... };
この場合の要件を次に示します。
接続コンテキスト型は、java.util.PropertyResourceBundle
を実装している関連クラスを指定するwith
句のtypeMap
属性で宣言されている必要があります。例では、SerContext
が次のように宣言されています。
#sql public static context SerContext with (typeMap="SerMap");
型マップ・リソースはRAW
列またはBLOB
列から、シリアライズ可能なJavaクラスまで、非標準マッピングを提供する必要があります。このマッピングは、次の形式のエントリで指定しますが、JavaクラスがRAW
とBLOB
のどちらの列にマップされているかによって形式が異なります。
oracle-class.java_class_name=JAVA_OBJECT RAW oracle-class.java_class_name=JAVA_OBJECT BLOB
キーワードoracle-class
は、これがOracle固有の拡張機能であることを示しています。例では、SerMap.properties
リソース・ファイルには次のエントリが含まれます。
oracle-class.SAddress=JAVA_OBJECT RAW oracle-class.pack.SPerson=JAVA_OBJECT BLOB oracle-class.packManager$InnerSPM=JAVA_OBJECT RAW
パッケージとクラス名の分割にはピリオド(.)を使用しますが、内部クラス名を分割するにはドル記号($)を使用する必要があります。
このOracle固有の拡張機能は、標準SQLData
型マップ・エントリと同じ型マップ・リソースに配置できます。
フィールド使用によるシリアライズ可能クラスのマッピングの指定
シリアライズ可能クラスに型マップを使用する別の方法として、シリアライズ可能クラスのstaticフィールドを使用して、型マッピングを指定できます。前述の例のSAddress
およびSPerson
クラスなど、java.io.Serializable
インタフェースを実装するクラスに次のフィールドのいずれかを追加できます。
public final static int _SQL_TYPECODE = oracle.jdbc.OracleTypes.RAW;
public final static int _SQL_TYPECODE = oracle.jdbc.OracleTypes.BLOB;
注意: 手動でのクラスへの_SQL_TYPECODE フィールド追加は、型マップ機能の使用に置き換えられました。 |
Javaオブジェクトのシリアライズにおける制限
シリアライズの効果について、認識しておく必要があります。2つのオブジェクトAおよびBが同じオブジェクトCを共有している場合、AおよびBは、そのシリアライズとその後のシリアライズ解除の際に、オブジェクトCのそれぞれのクローンをポイントすることになります。共有は解除されます。
さらに、与えられたJavaクラスに対して宣言できるシリアライズは、RAW
またはBLOB
の1種類のみです。SQLJトランスレータは、実際の使用方法がRAW
またはBLOB
のいずれかに適合することのみをチェックします。
RAW
列では、サイズが制限されています。シリアライズしたJavaオブジェクトが、列のサイズを超えると、ランタイム・エラーが発生します。
BLOB
列の列サイズ制限がより緩やかです。シリアライズされたJavaオブジェクトのBLOB
列への書込みは、Oracle JDBC Oracle Call Interface(OCI)ドライバおよびOracle JDBC Thinドライバでサポートされます。BLOB
列からのシリアライズされたオブジェクトの取得は、Oracle9i 以上のすべてのOracle JDBCドライバでサポートされています。
最後に、シリアライズされたJavaオブジェクトをこの方法で処理することは、Oracle固有の拡張機能であり、Oracle SQLJランタイムと、デフォルトのOracle固有コード生成(変換時の-codegen=oracle
)またはISO標準コード生成(-codegen=iso
)の場合はOracle固有のプロファイルのカスタマイズが必要です。
注意: この特定のシリアライズ・メカニズムの実装では、JDBC型マップは使用しません。BLOB またはRAW に対するマップは、変換時にカスタマイズされたOracleのプロファイルにハードコードされるか、Javaコードに直接生成されます。 |
oracle.sql.STRUCT
、oracle.sql.REF
またはoracle.sql.ARRAY
以外のoracle.sql.*
型にマッピングするカスタムJavaクラスの定義例は、「ORAData実装のその他の使用例」を参照してください。
RAW
フィールドに対してJavaオブジェクトのシリアライズおよびシリアライズ解除を行う場合の例では、カスタムJavaクラスをoracle.sql.RAW
型にマッピングしています。これは、BLOB
フィールドにも同様に当てはまり、カスタムJavaクラスをoracle.sql.BLOB
型にマッピングします。
ここでは、このようなアプリケーションの例として、ORAData
インタフェースを実装し、汎用形式のカスタムJavaクラスに準拠するSerializableDatum
クラスの作成について説明します。この例では、SerializableDatum
の開発手順を詳細に示してから、サンプル・コード全体を示します。
注意: このアプリケーションでは、java.io 、java.sql 、oracle.sql およびoracle.jdbc パッケージのクラスを使用しています。インポート文はここには含まれていません。 |
まず、このクラスのスケルトンから始めます。
public class SerializableDatum implements ORAData { // Client methods for constructing and accessing the Java object public Datum toDatum(java.sql.Connection c) throws SQLException { // Implementation of toDatum() } public static ORADataFactory getORADataFactory() { return FACTORY; } private static final ORADataFactory FACTORY = // Implementation of an ORADataFactory for SerializableDatum // Construction of SerializableDatum from oracle.sql.RAW public static final int _SQL_TYPECODE = OracleTypes.RAW; }
SerializableDatum
自体では、ORADataFactory
インタフェースが実装されることはありませんが、このクラスのgetORADataFactory()
メソッドを使用すると、このインタフェースを実装したstaticメンバーが戻されます。
_SQL_TYPECODE
を、OracleTypes.RAW
に設定します(データベースに対する読取りおよび書込みに使用されるデータ型であるため)。SQLJトランスレータは、この型コード情報に基づき、オンラインで型チェックを行い、ユーザー定義のJava型とSQL型間の互換性を検証します。
次の処理を行うクライアント・メソッドを定義します。
SerializableDatum
オブジェクトの作成
SerializableDatum
オブジェクトの設定
SerializableDatum
オブジェクトからのデータの取得
// Client methods for constructing and accessing a SerializableDatum private Object m_data; public SerializableDatum() { m_data = null; } public void setData(Object data) { m_data = data; } public Object getData() { return m_data; }
toDatum()
メソッドを実装して、SerializableDatum
オブジェクトからoracle.sql.RAW
オブジェクトへデータをシリアライズします。toDatum()
の実装では、m_data
フィールドのオブジェクトをoracle.sql.RAW
インスタンスとしてシリアライズした表現で戻す必要があります。
// Implementation of toDatum() try { ByteArrayOutputStream os = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(os); oos.writeObject(m_data); oos.close(); return new RAW(os.toByteArray()); } catch (Exception e) { throw new SQLException("SerializableDatum.toDatum: "+e.toString()); }
oracle.sql.RAW
オブジェクトからSerializableDatum
オブジェクトへのデータ変換を実装します。この段階で、データをシリアライズ解除します。
// Constructing SerializableDatum from oracle.sql.RAW private SerializableDatum(RAW raw) throws SQLException { try { InputStream rawStream = new ByteArrayInputStream(raw.getBytes()); ObjectInputStream is = new ObjectInputStream(rawStream); m_data = is.readObject(); is.close(); } catch (Exception e) { throw new SQLException("SerializableDatum.create: "+e.toString()); } }
ORADataFactory
を実装します。この例では、無名クラスとして実装します。
// Implementation of an ORADataFactory for SerializableDatum new ORADataFactory() { public ORAData create(Datum d, int sqlCode) throws SQLException { if (sqlCode != _SQL_TYPECODE) { throw new SQLException ("SerializableDatum: invalid SQL type "+sqlCode); } return (d==null) ? null : new SerializableDatum((RAW)d); } };
ここでは、前項で作成したSerializableDatum
クラスのインスタンスをホスト変数およびイテレータ列として、SQLJアプリケーションで使用する方法を示します。
次の表定義を想定します。
CREATE TABLE PERSONDATA (NAME VARCHAR2(20) NOT NULL, INFO RAW(2000));
次に、SerializableDatum
インスタンスをホスト変数として使用します。
... SerializableDatum pinfo = new SerializableDatum(); pinfo.setData ( new Object[] {"Some objects", new Integer(51), new Double(1234.27) } ); String pname = "MILLER"; #sql { INSERT INTO persondata VALUES(:pname, :pinfo) }; ...
次に、SerializableDatum
を名前付きイテレータの列として使用する例を示します。
#sql iterator PersonIter (SerializableDatum info, String name); ... PersonIter pcur; #sql pcur = { SELECT * FROM persondata WHERE info IS NOT NULL }; while (pcur.next()) { System.out.println("Name:" + pcur.name() + " Info:" + pcur.info()); } pcur.close(); ...
次に、前項で詳細手順を示したSerializableDatum
クラスのすべてのコードを示します。
import java.io.*; import java.sql.*; import oracle.sql.*; import oracle.jdbc.*; public class SerializableDatum implements ORAData { // Client methods for constructing and accessing a SerializableDatum private Object m_data; public SerializableDatum() { m_data = null; } public void setData(Object data) { m_data = data; } public Object getData() { return m_data; } // Implementation of toDatum() public Datum toDatum(Connection c) throws SQLException { try { ByteArrayOutputStream os = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(os); oos.writeObject(m_data); oos.close(); return new RAW(os.toByteArray()); } catch (Exception e) { throw new SQLException("SerializableDatum.toDatum: "+e.toString()); } } public static ORADataFactory getORADataFactory() { return FACTORY; } // Implementation of an ORADataFactory for SerializableDatum private static final ORADataFactory FACTORY = new ORADataFactory() { public ORAData create(Datum d, int sqlCode) throws SQLException { if (sqlCode != _SQL_TYPECODE) { throw new SQLException( "SerializableDatum: invalid SQL type "+sqlCode); } return (d==null) ? null : new SerializableDatum((RAW)d); } }; // Constructing SerializableDatum from oracle.sql.RAW private SerializableDatum(RAW raw) throws SQLException { try { InputStream rawStream = new ByteArrayInputStream(raw.getBytes()); ObjectInputStream is = new ObjectInputStream(rawStream); m_data = is.readObject(); is.close(); } catch (Exception e) { throw new SQLException("SerializableDatum.create: "+e.toString()); } } public static final int _SQL_TYPECODE = OracleTypes.RAW; }
SQLJでは、弱い型指定のオブジェクト、参照およびコレクションを使用できます。これらのクラスの使用は一般的には推奨されておらず、使用方法も制限されますが、便利な場合もあります。たとえば、汎用コードを記述して、どのようなSTRUCT
またはREF
でも使用できます。
ここでは、次の項目について説明します。
Oracleのオブジェクト、参照またはコレクションをSQLJアプリケーションで使用する場合は、強い型指定のカスタム・オブジェクト・クラス、参照クラスまたはコレクション・クラス(ORAData
インタフェースを実装したクラス)または強い型指定のカスタム・オブジェクト・クラス(SQLData
インタフェースを実装したクラス)を使用するかわりに、弱い型指定の汎用java.sql
インスタンスまたはoracle.sql
インスタンスを使用できます。ただし、SQLData
実装をカスタム・オブジェクト・クラスとして使用した場合、弱い型指定のカスタム参照インスタンスしか使用できません。
Oracle SQLJ実装では、イテレータ列またはホスト式に対して、次に示した弱い型指定を使用できます。
java.sql.Struct
またはoracle.sql.STRUCT
(オブジェクトの場合)
java.sql.Ref
またはoracle.sql.REF
(オブジェクト参照の場合)
java.sql.Array
またはoracle.sql.ARRAY
(コレクションの場合)
ホスト式の場合は、次の方法で使用できます。
入力ホスト式として
INTO
リストで出力ホスト式として
こうした弱い型指定は、通常は使用しないようにしてください。SQLJの強い型指定のパラダイムのあらゆるメリットが損なわれるためです。
STRUCT
オブジェクト内の各属性またはARRAY
オブジェクト内の各要素がoracle.sql.Datum
オブジェクトに格納されます。基礎となるデータの形式は、Datum
の適切なoracle.sql.*
サブタイプ(oracle.sql.NUMBER
やoracle.sql.CHAR
など)です。STRUCT
オブジェクト内の属性は匿名です。STRUCT
およびARRAY
クラスは汎用クラスであるため、これらのクラスのインスタンスに対してオブジェクトまたはコレクションの読取りや書込みを行う際は、SQLJで型チェックを行うことはできません。
一般的には、オブジェクト、参照およびコレクションに対してカスタムJavaクラスの使用をお薦めします。可能な場合は、JPublisherで生成したクラスを使用してください。
弱い型指定のオブジェクト(Struct
またはSTRUCT
インスタンス)、参照(Ref
またはREF
のインスタンス)、またはコレクション(Array
またはARRAY
のインスタンス)は、次の状況では、ホスト式では使用できません。
IN
パラメータとして(NULLの場合)
ストアド・プロシージャまたはストアド・ファンクションのコールで、OUT
またはINOUT
パラメータとして
ストアド・ファンクションの結果式で、OUT
パラメータとして
これらのパラメータとして使用できない理由は、元のSQL型の名前(Person
など)を特定できないからです。Oracle JDBCドライバは、元のSQL型の名前を使用して、Javaのユーザー定義型のインスタンスを生成します。
Oracle OPAQUE型は抽象データ型です。単なる一連のバイトとして実装されたデータの場合、内部表現は公開されません。通常、OPAQUE型はOracleで提供され、カスタマによる実装はありません。
OPAQUE型は、基本的な点でオブジェクト型に類似しています。つまり、staticメソッド、インスタンスおよびインスタンス・メソッドの概念が類似しています。一般的に、状態や内部バイト表現を操作できるのは、OPAQUE型を使用して提供されるメソッドのみです。Javaでは、oracle.sql.OPAQUE
として、またはoracle.sql.ORAData
インタフェースを実装しているカスタム・クラスとして、OPAQUE型を表現できます。クライアント側では、Javaコードを実装してバイトを操作できます(バイト・パターンが判明していることが前提です)。Oracle Database 11g JPublisherユーティリティを使用すると、このようにORAData
を実装するカスタム・クラスを作成して、データベースへのラウンドトリップを繰り返すことなくデータを操作できます。
関連項目: 『Oracle Database JPublisherユーザーズ・ガイド』 |
OPAQUE型の主な例は、Oracle Database 11g で提供しているXMLType
です。Oracleが提供する型によって、データベースのXMLデータをネイティブに処理することが容易になります。
SYS.XMLType
によって次の機能が提供され、Javaのoracle.xdb.XMLType
クラスを介して公開されます。
表またはビューの列のデータ型として使用できます。XMLType
にはあらゆるコンテンツを格納できますが、XMLコンテンツを最適に格納するように設計されています。そのインスタンスはSQLでXMLドキュメントを表現できます。
XMLコンテンツの操作を行う組込みメンバー・ファンクションを含むSQL APIがあります。たとえば、XMLType
ファンクションを使用すると、Oracle Database 11g インスタンスに格納されているXMLデータの作成、問合せ、抽出および索引付けができます。
ストアド・プロシージャで、パラメータ、戻り値および変数に使用できます。
この機能は、PL/SQL、JavaおよびC(OCI)で提供されるAPIを介して使用することもできます。
関連項目: 『Oracle XML DB開発者ガイド』 |