アプリケーション開発の手引き

列タイプとしての構造型の作成と使用

このセクションでは、ユーザー定義の構造型を列というタイプとして使用することに関係する主なタスクを説明します。このセクションをお読みになる前に、 構造型の概説の資料に精通しておいてください。

構造型インスタンスの列への挿入

構造型は、表、視点、または列のコンテキストで使用することができます。構造型を作成する時に、ユーザー定義タイプの振る舞いとタイプ属性の両方をカプセル化することができます。タイプの振る舞いを組み込むには、 CREATE TYPE または ALTER TYPE ステートメントを使用して、メソッド・シグニチャーを指定します。メソッドの作成方法の詳細については、ユーザー定義関数 (UDF) およびメソッドを参照してください。

図 15 は、このセクションで例として使用されているタイプ階層を示しています。ルート・タイプは Address_t です。これには、それぞれの国での住所の形式のいくつかの局面を反映する追加の属性を持つ 3 つのサブタイプがあります。

図 15. Address_t タイプの構造型階層


Address_t タイプの構造型階層

   CREATE TYPE Address_t AS
      (street VARCHAR(30),
      number CHAR(15),
      city VARCHAR(30),
      state VARCHAR(10))
      MODE DB2SQL;
   CREATE TYPE Germany_addr_t UNDER Address_t AS
      (family_name VARCHAR(30))
      MODE DB2SQL;
   CREATE TYPE Brazil_addr_t UNDER Address_t AS
      (neighborhood VARCHAR(30))
      MODE DB2SQL;
   CREATE TYPE US_addr_t UNDER Address_t AS
      (zip CHAR(10))
      MODE DB2SQL;

構造型列を持つ表の定義

データ・レコードの中での構造型のレイアウトに関心がなければ、構造型の列を持つ表の作成については、追加の構文はありません。たとえば、次のステートメントは、 Address_t タイプの列を Customer_List 非タイプ付き表に追加します。

   ALTER TABLE Customer_List
      ADD COLUMN Address Address_t;

これで、Address_t のインスタンスまたは Address_t のサブタイプをこの表に保管できるようになりました。構造型の挿入方法の詳細については、 構造型値が入っている行の挿入を参照してください。

データ・レコード内での構造型のレイアウトに関心がある場合は、 CREATE TYPE ステートメントの中で INLINE LENGTH 文節を使用して、行の中のその他の値と一緒にインラインで保管する、構造型列のインスタンスの最大サイズを指示することができます。 INLINE LENGTH 文節の詳細については、 SQL 解説書 の中の CREATE TYPE (構造化) ステートメントを参照してください。

構造型属性を持つタイプの定義

タイプは、構造型属性を持つものとして作成できます。あるいは、そのような属性を追加または除去するようタイプを (使用される前に) 更新できます。たとえば、次の CREATE TYPE ステートメントには、タイプ Address_t の属性が含まれています。

   CREATE TYPE Person_t AS
      (Name VARCHAR(20),
      Age INT,
      Address Address_t)
      REF USING VARCHAR(13)
      MODE DB2SQL;

Person_t は、表のタイプ、正規表の中の列のタイプ、または別の構造型の属性として使用できます。

構造型値が入っている行の挿入

構造型を作成すると、DB2 はそのタイプのための constructor メソッドを自動的に生成して、そのタイプの属性のための mutator メソッドと observer メソッドを生成します。これらのメソッドを使用して、構造型のインスタンスを作成し、これらのインスタンスを表の列に挿入することができます。

新しい行を Employee タイプ付き表に追加して、その行に住所を入れるとします。組み込みデータ・タイプの場合と同様に、 VALUES 文節を指定した INSERT を使用してこの行を追加できます。しかし、住所に挿入する値を指定する時は、次のように、システムが提供する constructor 関数を呼び出してその値を作成する必要があります。

   INSERT INTO Employee (Oid, Name, Age, SerialNum, Salary, Dept, Address)
      VALUES(Employee_t('m'), 'Marie', 35, 005, 55000, BusinessUnit_t(2),
      US_addr_t ( ) (1)
         ..street('Bakely Avenue') (2)
         ..number('555') (3)
         ..city('san Jose') (4)
         ..state('CA') (5)
         ..zip('95141')); (6)

前述のステートメントは、次のタスクを実行することによって、 US_addr_t タイプのインスタンスを作成します。

  1. US_addr_t() の呼び出しは、すべての属性がヌル値に設定されたタイプのインスタンスを作成するために、 US_addr_t タイプのための constructor 関数を呼び出す。
  2. ..street('Bakely Avenue') の呼び出しは、値を 'Bakely Avenue' に設定するために、 street 属性のための mutator メソッドを呼び出す。
  3. ..number('555') の呼び出しは、値を '555' に設定するために、 number 属性のための mutator メソッドを呼び出す。
  4. ..city('san Jose') の呼び出しは、値を 'san Jose' に設定するために、 city 属性のための mutator メソッドを呼び出す。
  5. ..state('CA') の呼び出しは、値を 'CA' に設定するために、 state 属性のための mutator メソッドを呼び出す。
  6. ..zip('95141') の呼び出しは、値を '95141' に設定するために、 zip 属性のための mutator メソッドを呼び出す。

Employee 表の中の列 Address のタイプが Address_t として定義されていますが、代用性の特性を活用して、その列に US_addr_t のインスタンスを挿入することができます。 US_addr_tAddress_t のサブタイプだからです。

構造型のインスタンスを作成する度に、構造型のそれぞれの属性のための mutator メソッドを明示的に呼び出さなくてもよいようにするために、すべての属性を初期化する独自の SQL の constructor 関数を定義することを考慮してください。次の例は、US_addr_t タイプのための SQL の constructor 関数の宣言です。

   CREATE FUNCTION US_addr_t
         (street Varchar(30),
         number Char(15),
         city Varchar(30),
         state Varchar(20),
         zip Char(10))
      RETURNS US_addr_t
      LANGUAGE SQL
      RETURN Address_t()..street(street)..number(number)
          ..city(city)..state(state)..zip(zip);

次の例は、前述の例の SQL の constructor 関数を呼び出して、 US_addr_t タイプのインスタンスを作成する方法を示しています。

   INSERT INTO Employee(Oid, Name, Age, SerialNum, Salary, Dept, Address)
      VALUES(Employee_t('m'), 'Marie', 35, 005, 55000, BusinessUnit_t(2),
         US_addr_t('Bakely Avenue', '555', 'San Jose', 'CA', '95141'));

構造型値の検索と変更

アプリケーションおよびユーザー定義の関数が、構造型列の中のデータにアクセスする方法はいくつかあります。オブジェクトを単一の値として扱う場合は、最初に transform 関数 を定義する必要があります。これは、ホスト言語プログラムへのマッピングの作成: transform 関数で説明されています。正しい transform 関数を定義した後は、他の任意の値も選択できますが、構造化オブジェクトを選択することができます。

   SELECT Name, Dept, Address
      FROM Employee
      WHERE Salary > 20000;

しかし、このセクションでは、 DB2 の組み込み observer メソッドおよび mutator メソッドを呼び出して、オブジェクトの個々の属性に明示的にアクセスする方法を説明します。組み込みメソッドを使用すれば、transform 関数を定義する必要はありません。

属性の検索

オブジェクトの個々の属性に明示的にアクセスするには、それらの属性に対して DB2 組み込み observer メソッドを呼び出します。 observer メソッドを使用すれば、オブジェクトを単一の値として扱うのではなく、属性を個別に検索することができます。

次の例は、 Address 列の定義済み静的タイプである Address_t に対して observer メソッドを呼び出すことによって、 Address 列の中のデータにアクセスします。

   SELECT Name, Dept, Address..street, Address..number, Address..city,
      Address..state
      FROM Employee
      WHERE Salary > 20000;
注:DB2 では、<type-name>..<method-name>() か、 <type-name>..<method-name> のどちらかを使用して、パラメーターのないメソッドを呼び出すことができます。ここで、type-name は構造型の名前を表し、 attribute-name はパラメーターがないメソッドの名前を表します。

observer メソッドを使用して、次のようにしてそれぞれの属性を選択してホスト変数に入れることもできます。

   SELECT Name, Dept, Address..street, Address..number, Address..city,
      Address..state
      INTO :name, :dept, :street, :number, :city, :state
      FROM Employee
      WHERE Empno = '000250';

サブタイプの属性へのアクセス

Employee 表では、住所に指定できるタイプが 4 つあり、それらは Address_tUS_addr_tBrazil_addr_t、および Germany_addr_t です。前述の例は、静的タイプ Address_t の属性だけにアクセスします。 Address_t のいずれかのサブタイプの値の属性にアクセスするには、特定のオブジェクトのタイプが US_addr_tGermany_addr_t、または Brazil_addr_t のいずれかであることを DB2 に示すために、 TREAT 式を使用しなければなりません。 TREAT 式は、次の照会の中で示されているように、構造型式をサブタイプのうちの 1 つにキャストします。

   SELECT Name, Dept, Address..street, Address..number, Address..city,
      Address..state,
      CASE
         WHEN Address IS OF (US_addr_t)
         THEN TREAT(Address AS US_addr_t)..zip
         WHEN Address IS OF (Germany_addr_t)
         THEN TREAT (Address AS Germany_addr_t)..family_name
         WHEN Address IS OF (Brazil_addr_t)
         THEN TREAT (Address AS Brazil_addr_t)..neighborhood
      ELSE NULL END
      FROM Employee
      WHERE Salary > 20000;
注:サブタイプの属性がすべて同じタイプである場合か、サブタイプの属性を同じタイプにキャストできる場合に、構造型のサブタイプを判別するのに使用できるのは前述の方法だけです。前述の例では、zipfamily_name、および neighborhood は、すべて VARCHAR タイプまたは CHAR タイプであるので、同じタイプにキャストすることができます。

TREAT 式または TYPE 述部の構文の詳細については、 SQL 解説書 を参照してください。

属性の変更

構造化列値の属性を変更するには、変更する属性のための mutator メソッドを呼び出します。たとえば、住所の street 属性を変更するには、 street のための変更後の値を指定した mutator メソッドを呼び出します。戻り値は、street の新しい値が指定された住所になります。次の例は、Employee 表の中の住所タイプを更新するために、 street という属性のための mutator メソッドを呼び出します。

   UPDATE Employee
      SET Address = Address..street('Bailey')
      WHERE Address..street = 'Bakely';

次の例は、前述の例と同じ更新を行いますが、更新する構造化列が指定されているわけではなく、 SET 文節が street という属性のための mutator メソッドに直接アクセスしています。

   UPDATE Employee
      SET Address..street = 'Bailey'
      WHERE Address..street = 'Bakely';

タイプについての情報を戻す

タイプに関連したその他の組み込み関数で説明されているように、組み込み関数を使用して、特定のタイプの名前、スキーマ、または初期タイプ ID を戻すことができます。次のステートメントは、 'Iris' という従業員に関連した住所値の正確なタイプを戻します。

   SELECT TYPE_NAME(Address)
      FROM Employee
      WHERE Name='Iris';

transform のタイプとの関連付け

通常 transform 関数は、FROM SQL transform 関数と TO SQL transform 関数の対で使用します。 FROM SQL 関数は、構造型オブジェクトを外部プログラムと交換可能なタイプに変換し、 TO SQL 関数はオブジェクトを構成します。 transform 関数を作成する時には、 transform 関数の論理対を 1 つのグループに入れます。 transform グループ 名によって、指定した構造型のためのこれらの関数の対を一意的に識別できます。

transform 関数を使用する前に、 CREATE TRANSFORM ステートメントを使用して、 transform 関数をグループ名およびタイプと関連付ける必要があります。 CREATE TRANSFORM ステートメントは、既存の関数 (1 つまたは複数) を識別して、その関数を transform 関数として使用できるようにします。次の例は、2 組みの関数が、タイプ Address_t のための transform 関数として使用されるように指定しています。このステートメントは、 func_groupclient_group という 2 つの transform グループを作成します。これらのグループは、それぞれが FROM SQL transform と TO SQL transform で構成されています。

   CREATE TRANSFORM FOR Address_t
      func_group ( FROM SQL WITH FUNCTION addresstofunc,
         TO SQL WITH FUNCTION functoaddress )
      client_group ( FROM SQL WITH FUNCTION stream_to_client,
         TO SQL WITH FUNCTION stream_from_client ) ;

CREATE TRANSFORM ステートメントにグループを追加することによって、 Address_t タイプに追加の関数を関連付けることができます。 transform 定義を更新するには、追加の関数を指定した CREATE TRANSFORM ステートメントを再発行する必要があります。たとえば、クライアント関数を異なるホスト言語プログラム用 (C 用、 Java 用など) にカスタマイズすることがあります。アプリケーションのパフォーマンスを最適化するために、 transform の対象をオブジェクト属性のサブセットだけに限定することもあります。あるいは、オブジェクト用のクライアントを表すものとして VARCHAR を使用する transform、 BLOB を使用する transform を用意することもあります。

transform 関数とタイプとの関連付けを解除するには、 SQL ステートメント DROP TRANSFORM を使用します。 DROP TRANSFORM ステートメントの実行後は、 transform 関数が削除されるわけではありませんが、このタイプのための transform 関数として使用されることはありません。次の例は、Address_t タイプのための transform 関数の特定のグループ func_group の関連付けを解除してから、 Address_t タイプのためのすべての transform 関数の関連付けを解除しています。

   DROP TRANSFORMS func_group FOR Address_t;
   DROP TRANSFORMS ALL FOR Address_t;

transform グループの命名についての推奨事項

transform グループ名は、修飾されていない 識別子です。つまり、特定のスキーマと関連付けられていないということです。 サブタイプ・データの DB2 からの検索 (バインドアウト) で説明されているように、サブタイプ・パラメーターを扱う transform を作成するのでない限り、すべての構造型のための transform グループ名を割り当てるべきではありません。同一プログラムまたは同一 SQL ステートメント内で、関連付けがなされていないさまざまなタイプを使用する必要があるかもしれないので、 transform グループは、transform 関数が実行するタスクに従って命名する必要があります。

一般的に transform グループの名前は、タイプ名に依存したものではなく、実行される関数を反映したもの、あるいは、transform 関数の論理を何らかの方法で反映したものとなっているべきです。実行される関数や関数の論理は、タイプ間で非常に異なっているものです。たとえば、TO および FROM SQL 関数 transform が定義されているグループに、 func_group または object_functions という名前を使用することができます。 TO および FROM SQL クライアント transform が入っているグループに、 client_group または program_group という名前を使用することができます。

次の例では、Address_t および Polygon タイプは、非常に異なる transform を使用していますが、同じ関数グループ名を使用しています。

   CREATE TRANSFORM FOR Address_t
      func_group (TO SQL WITH FUNCTION functoaddress,
      FROM SQL WITH FUNCTION addresstofunc );
   CREATE TRANSFORM FOR Polygon
      func_group (TO SQL WITH FUNCTION functopolygon,
      FROM SQL WITH FUNCTION polygontofunc);

transform グループを指定する必要のある場合で説明されているように、ふさわしい状況のもとで transform グループを func_group に設定した後は、 Address_t または Polygon をバインドインするかバインドアウトする度に、 DB2 は正しい transform 関数を呼び出します。
制限:transform グループの名前は 'SYS' というストリングで始めないでください。これは DB2 が使用する予約済みのグループを表します。

外部関数または外部メソッドを定義する場合で、transform グループ名を指定しない場合は、 DB2 は DB2_FUNCTION という名前を使おうとし、このグループ名は指定の構造型のために指定されたものと想定します。指定の構造型を参照するクライアント・プログラムをプリコンパイルする時にグループ名を指定しない場合は、 DB2 は DB2_PROGRAM というグループ名を使おうとし、このグループ名はこの構造型のために定義されたものと想定します。

このデフォルトの振る舞いは、便利なこともありますが、より複雑なデータベース・スキーマでは、 transform グループ名のためのもう少し詳細な規則が必要であると感じるかもしれません。たとえば、このデフォルトの振る舞いは、タイプをバインドアウトするさまざまな言語にさまざまなグループ名を使用する点で役立ちます。

transform グループを指定する必要のある場合

指定の構造型のために定義されている transform グループが多数ある場合は、プログラムまたは特定の SQL ステートメントでは、その構造型のために使用する transform のグループを指定する必要があります。 transform グループを指定する必要がある状況には、次の 3 つの状況があります。

外部ルーチン用の transform グループの指定

CREATE FUNCTION および CREATE METHOD ステートメントでは、 TRANSFORM GROUP 文節を指定することができます。この文節は LANGUAGE 文節の値が SQL ではない場合にのみ有効になります。 SQL 言語関数では transform は必要ありませんが、外部関数では必要です。 TRANSFORM GROUP 文節を使用すれば、構造型のパラメーターや結果に使用される TO SQL および FROM SQL transform が入っている transform グループを、指定の関数またはメソッドに指定することができます。次の例では、CREATE FUNCTION および CREATE METHOD ステートメントは、 transform グループ func_group を、 TO SQL および FROM SQL transform に指定しています。

   CREATE FUNCTION stream_from_client (VARCHAR (150))
      RETURNS Address_t
      ...
      TRANSFORM GROUP func_group
      EXTERNAL NAME 'addressudf!address_stream_from_client'
      ...
   CREATE METHOD distance ( point )
      FOR polygon
      RETURNS integer
      :
      TRANSFORM GROUP func_group ;

動的 SQL 用の transform グループの設定

動的 SQL を使用する場合は、 CURRENT DEFAULT TRANSFORM GROUP 特殊レジスターを設定できます。この特殊レジスターは、静的 SQL ステートメントには使用されません。また、外部関数またはメソッドとのパラメーターや結果の交換にも使用されません。 SET CURRENT DEFAULT TRANSFORM GROUP ステートメントは、動的 SQL ステートメントのためのデフォルト transform グループを設定するために使用します。

   SET CURRENT DEFAULT TRANSFORM GROUP = client_group;

静的 SQL 用の transform グループの設定

静的 SQL については、PRECOMPILE または BIND コマンドで TRANSFORM GROUP オプションを使用して、さまざまなタイプの値をホスト・プログラムと交換するために、静的 SQL ステートメントが使用する静的 transform グループを指定します。静的 transform グループは、動的 SQL ステートメントには適用されません。また、外部関数またはメソッドとのパラメーターや結果の交換にも適用されません。 PRECOMPILE または BIND コマンドで静的 transform グループを指定するには、次のようにして TRANSFORM GROUP 文節を使用します。

   PRECOMPILE ...
   TRANSFORM GROUP client_group
   ... ;

PRECOMPILE および BIND コマンドの詳細については、 コマンド解説書 を参照してください。

ホスト言語プログラムへのマッピングの作成: transform 関数

アプリケーションは、1 つのオブジェクト全体を直接選択することはできませんが、 属性の検索で説明されているように、オブジェクトの個々の属性を選択してアプリケーションに入れることはできます。アプリケーションは、通常はオブジェクト全体を直接挿入することはありませんが、 constructor 関数の呼び出しの結果を挿入することはできます。

   INSERT INTO Employee(Address) VALUES (Address_t());

サーバー・アプリケーションとクライアント・アプリケーションの間で全オブジェクトを交換するには、通常は transform 関数 を作成する必要があります。

ある transform 関数は、 DB2 がオブジェクトの内容にアクセスできるよう正しく定義された形式にオブジェクトを変換する方法、または、DB2 がオブジェクトをバインドアウト する方法を定義します。別の transform 関数は、DB2 がデータベースに保管されるオブジェクトを戻す方法、または、DB2 がオブジェクトをバインドイン する方法を定義します。オブジェクトをバインドアウトする transform のことを FROM SQL transform 関数といい、列オブジェクトをバインドインする transform のことを TO SQL transform 関数といいます。

ルーチン、または外部 UDF および外部メソッドにオブジェクトを渡すための transform の種類は、オブジェクトをクライアント・アプリケーションに渡す transform の種類よりも多くなります。これは、オブジェクトを外部ルーチンに渡す時は、オブジェクトを分解 して、パラメーターのリストとしてルーチンに渡すからです。クライアント・アプリケーションでは、オブジェクトを BLOB などの単一の組み込みタイプに変換する必要があります。このプロセスのことを、オブジェクトの符号化といいます。これら 2 種類の transform は、多くの場合一緒に使用されます。

transform 関数を特定の構造型と関連付けるには、SQL ステートメント CREATE TRANSFORM を使用します。 CREATE TRANSFORM ステートメント内で、 transform 関数は対にされて transform グループ と呼ばれるものに入れられます。これによって、特定の変換目的に使用される関数を識別しやすくなります。 1 つの transform グループに入れることができるのは、特定の 1 つのタイプにつき、 1 つの FROM SQL transform と 1 つの TO SQL transform だけです。
注:次のトピックでは、アプリケーションが、常に Address_t などの既知の正確なタイプを受け取る単純な事例を取り上げます。外部ルーチンまたはクライアント・プログラムが、 Address_tBrazil_addr_tGermany_addr_t、または US_addr_t を受け取るような実際にありそうなシナリオについては説明されていません。しかし、外部ルーチンまたはクライアント・プログラムが、すべてのタイプまたはサブタイプを動的に処理する必要のある複雑な事例に基本プロセスを適用しようとする場合は、事前に基本プロセスを理解しておく必要があります。サブタイプ・インスタンスを動的に処理する方法の詳細については、 サブタイプ・データの DB2 からの検索 (バインドアウト) を参照してください。

オブジェクトの外部ルーチンとの交換: function transform

このセクションでは、 function transform という transform の特定のタイプを説明します。 DB2 は、これらの TO SQL および FROM SQL function transform を使用して、外部ルーチンとの間でオブジェクトをやり取りします。 SQL を本体として持つルーチンについては transform を使用する必要はありません。しかし、オブジェクトのクライアント・プログラムとの交換: client transformで説明されているように、 DB2 は、クライアント・プログラムとの間でオブジェクトをやり取りするプロセスの一部として、これらの関数を使用することがよくあります。

次の例は、MYUDF という外部 UDF を呼び出す SQL ステートメントを発行します。住所を入力パラメーターとして取り、(たとえば、通りの名前の変更を反映するために) 住所を変更して、変更された住所を戻します。

   SELECT MYUDF(Address)
   FROM PERSON;

図 16 は、DB2 が住所を処理する方法を示しています。

図 16. 構造型パラメーターの外部ルーチンとの交換


構造型パラメーターの外部ルーチンとの交換

  1. FROM SQL transform 関数は、構造型を基本属性の順序づけられたセットに分解します。これによって、ルーチンは、タイプが基本組み込みデータ・タイプであるパラメーターの単純なリストとして、オブジェクトを受け取ることができるようになります。たとえば、住所オブジェクトを外部ルーチンに渡すとします。 Address_t の属性は、順に VARCHAR、CHAR、 VARCHAR、VARCHAR となっています。このオブジェクトをルーチンに渡すための FROM SQL transform は、このオブジェクトを入力として受け入れ、 VARCHAR、CHAR、VARCHAR、VARCHAR を戻す必要があります。次にこれらの出力は、 4 つの対応するヌル標識パラメーターと構造型のための 1 つのヌル標識と一緒に、 4 つの別々のパラメーターとして外部ルーチンに渡されます。 Address_t タイプを戻すすべての関数でパラメーターの順序が同じである限り、 FROM SQL 関数内のパラメーターの順序は重要ではありません。詳細については、構造型パラメーターを外部ルーチンに渡すを参照してください。
  2. 外部ルーチンは分解された住所を入力パラメーターとして受け入れ、これらの値に対して処理を行ってから、属性を出力パラメーターとして戻します。
  3. TO SQL transform 関数は、MYUDF から戻される VARCHAR、CHAR、VARCHAR、VARCHAR パラメーターを、タイプ Address_t のオブジェクトに変換する必要があります。言い換えると、TO SQL transform 関数は、 4 つのパラメーターとすべての対応するヌル標識パラメーターを、ルーチンからの出力値として取る必要があるということです。 TO SQL 関数は、構造化オブジェクトを構成し、次に、指定された値を使用して属性を変化させます。
注:MYUDF も構造型タイプを戻す場合、 SELECT 文節の中で UDF が使用されている時は、結果として生じる構造型は別の transform 関数によって変換される必要があります。別の transform 関数が作成されないようにするには、次の例のように、observer メソッドを指定した SELECT ステートメントを使用します。

   SELECT Name
      FROM Employee
      WHERE MYUDF(Address)..city LIKE 'Tor%';

SQL を本体として持つルーチンを使用した function transform の実装

オブジェクトを外部ルーチンと交換する時にオブジェクトを分解して構成するには、 SQL で作成されたユーザー定義の関数を使用します。この関数のことを SQL を本体として持つルーチン といいます。 SQL を本体として持つルーチンを作成するには、 LANGUAGE SQL 文節を指定して CREATE FUNCTION ステートメントを発行します。

SQL を本体として持つ関数では、変換を行うために constructor、observer、および mutator を使用できます。 図 16 で示されているように、この SQL を本体として持つ transform は、 SQL ステートメントと外部関数との間に介在します。 FROM SQL transform は、オブジェクトを SQL パラメーターとして取り、構造型の属性を表す値の行を戻します。 SQL を本体として持つ関数を使用した、住所オブジェクトのための有効な FROM SQL transform 関数の例は、次のとおりです。

   CREATE FUNCTION addresstofunc (A Address_t) (1)
      RETURNS ROW  (Street VARCHAR(30), Number CHAR(15),
         City VARCHAR(30), State (VARCHAR(10)) (2)
      LANGUAGE SQL (3)
      RETURN VALUES (A..Street, A..Number, A..City, A..State) (4)

次のリストは、前述の CREATE FUNCTION ステートメントの構文を説明しています。

  1. この関数のシグニチャーは、タイプ Address_t のオブジェクトという 1 つのパラメーターを受け入れることを示しています。
  2. RETURNS ROW 文節は、この関数が、 StreetNumberCity、および State という 4 つの列を含む行を戻すことを示しています。
  3. LANGUAGE SQL 文節は、これが外部関数ではなく、SQL を本体として持つ関数であることを示しています。
  4. RETURN 文節は、関数本体の先頭をマークしています。本体は、Address_t オブジェクトのそれぞれの属性のための observer メソッドを呼び出す 1 つの VALUES 文節で構成されています。 observer メソッドは、オブジェクトを基本タイプのセットに分解します。この関数は、この基本タイプのセットを行として戻します。

DB2 には、開発者がこの関数を transform 関数として使用するつもりであることは分かりません。この関数を使用する transform グループを作成して、ふさわしい状況でその transform グループを指定するまでは、 DB2 はこの関数を transform 関数として使用することはできません。詳細については、transform のタイプとの関連付けを参照してください。

TO SQL transform は、FROM SQL 関数と反対のことを行います。 TO SQL transform は、ルーチンからのパラメーターのリストを入力として取り、構造型のインスタンスを戻します。次の FROM SQL 関数は、オブジェクトを構成するために、 Address_t タイプのための constructor 関数を呼び出します。

   CREATE FUNCTION functoaddress (street VARCHAR(30), number CHAR(15),
                                  city VARCHAR(30), state VARCHAR(10)) (1)
      RETURNS Address_t (2)
      LANGUAGE SQL
      CONTAINS SQL
      RETURN
         Address_t()..street(street)..number(number)
         ..city(city)..state(state) (3)

次のリストは、前述のステートメントの構文を説明しています。

  1. 関数は、基本タイプ属性を取ります。
  2. 関数は、Address_t 構造型を戻します。
  3. 関数は、Address_t のための constructor と、それぞれの属性のための mutator を呼び出すことによって、入力タイプからオブジェクトを構成します。

住所を戻すすべての関数でパラメーターの順序が同じである限り、 FROM SQL 関数内のパラメーターの順序は重要ではありません。

構造型パラメーターを外部ルーチンに渡す

構造型パラメーターを外部ルーチンに渡す時は、それぞれの属性のためのパラメーターを渡す必要があります。それぞれのパラメーターのためのヌル標識と、構造型のためのヌル標識を渡す必要があります。次の例は、構造型 Address_t を受け入れ、基本タイプを戻します。

   CREATE FUNCTION stream_to_client (Address_t)
      RETURNS VARCHAR(150) ...

外部ルーチンは、Address_t タイプのインスタンスのためのヌル標識 (address_ind) と、 Address_t タイプのそれぞれの属性につき 1 つのヌル標識を受け入れる必要があります。 VARCHAR 出力パラメーターのためのヌル標識もあります。次のコードは、UDF を実装する関数のための C 言語関数のヘッダーを表しています。

   void SQL_API_FN stream_to_client(
   /*decomposed address*/
      SQLUDF_VARCHAR *street,
      SQLUDF_CHAR *number,
      SQLUDF_VARCHAR *city,
      SQLUDF_VARCHAR *state,
      SQLUDF_VARCHAR *output,
   /*null indicators for type attributes*/
      SQLUDF_NULLIND *street_ind,
      SQLUDF_NULLIND *number_ind,
      SQLUDF_NULLIND *city_ind,
      SQLUDF_NULLIND *state_ind,
   /*null indicator for instance of the type*/
      SQLUDF_NULLIND *address_ind,
   /*null indicator for the VARCHAR output*/
      SQLUDF_NULLIND *out_ind,
      SQLUDF_TRAIL_ARGS)

構造型パラメーターを外部ルーチンに渡す: complex

ルーチンが st1st2 という 2 つの異なる構造型パラメーターを受け入れ、 st3 という別の構造型を戻すとします。

   CREATE FUNCTION myudf (int, st1, st2)
      RETURNS st3

表 14. myudf パラメーターの属性
ST1 ST2 ST3
st1_att1 VARCHAR st2_att1 VARCHAR st3_att1 INTEGER
st2_att2 INTEGER st2_att2 CHAR st3_att2 CLOB

st2_att3 INTEGER

次のコードは、UDF を実装するルーチンのための C 言語のヘッダーを表しています。引き数には、次のように、変数と、分解された構造型の属性のヌル標識および構造型のそれぞれのインスタンスのためのヌル標識が入っています。

  void SQL_API_FN myudf(
      SQLUDF_INTEGER *INT,
   /* Decompose st1 input */
      SQLUDF_VARCHAR *st1_att1,
      SQLUDF_INTEGER  *st1_att2,
   /* Decompose st2 input */
      SQLUDF_VARCHAR *st2_att1,
      SQLUDF_CHAR   *st2_att2,
      SQLUDF_INTEGER *st2_att3,
   /* Decompose st3 output */
      SQLUDF_VARCHAR *st3_att1out,
      SQLUDF_CLOB   *st3_att2out,
   /* Null indicator of integer*/
      SQLUDF_NULLIND *INT_ind,
   /* Null indicators of st1 attributes and type*/
      SQLUDF_NULLIND *st1_att1_ind,
      SQLUDF_NULLIND *st1_att2_ind,
      SQLUDF_NULLIND *st1_ind,
   /* Null indicators of st2 attributes and type*/
      SQLUDF_NULLIND *st2_att1_ind,
      SQLUDF_NULLIND *st2_att2_ind,
      SQLUDF_NULLIND *st2_att3_ind,
      SQLUDF_NULLIND *st2_ind,
   /* Null indicators of st3_out attributes and type*/
      SQLUDF_NULLIND *st3_att1_ind,
      SQLUDF_NULLIND *st3_att2_ind,
      SQLUDF_NULLIND *st3_ind,
   /* trailing arguments */
      SQLUDF_TRAIL_ARGS
   )

オブジェクトのクライアント・プログラムとの交換: client transform

このセクションでは、client transform について説明します。 client transform は、構造型をクライアント・アプリケーション・プログラムとの間で交換します。

たとえば、次の SQL ステートメントを実行するとします。

   ...
   SQL TYPE IS Address_t AS VARCHAR(150) addhv;
   ...
   EXEC SQL SELECT Address
      FROM Person
      INTO :addhv
      WHERE AGE > 25
   END EXEC;

図 17 は、住所をクライアント・プログラムにバインドアウトするプロセスを示しています。

図 17. 構造型のクライアント・アプリケーションへのバインドアウト


構造型のクライアント・アプリケーションへのバインドアウト

  1. オブジェクトを基本タイプ属性に分解するために、最初にオブジェクトを FROM SQL function transform に渡す必要があります。
  2. FROM SQL client transform は、値を符号化して、 VARCHAR または BLOB などの単一の組み込みタイプにする必要があります。これによって、クライアント・プログラムは、値全体を単一のホスト変数として受け取ることができます。

    この符号化は、(必要な調整に備えて) 属性を記憶域の連続区域にコピーすることと同じほど単純に行えます。通常、属性の符号化と分解は SQL を使用して行うことはできないので、 client transform は外部 UDF として作成されます。

    プラットフォーム間でデータを処理する方法の詳細については、 データ変換についての考慮事項を参照してください。

  3. クライアント・プログラムが値を処理します。

図 18 は、住所をデータベースに戻す逆のプロセスを示しています。

図 18. クライアントからの構造型のバインドイン


クライアントからの構造型のバインドイン

  1. クライアント・アプリケーションは、住所を TO SQL client transform が処理できる形式に符号化します。
  2. TO SQL client transform は、単一の組み込みタイプをその基本タイプ属性のセットに分解します。そしてこのセットは TO SQL function transform への入力として使用されます。
  3. TO SQL function transform は、住所を構成してそれをデータベースに戻します。

外部 UDF を使用した client transform の実装

client transform をその他の外部 UDF と同じ方法で登録します。たとえば、住所のために適切な符号化と複号を行う外部 UDF を作成したと想定しましょう。 FROM SQL client transform には from_sql_to_client、 TO SQL client transform には to_sql_from_client という名前を付けたとします。この両方の事例では、関数の出力は、ふさわしい FROM SQL および TO SQL function transform が入力として使用できる形式になります。

   CREATE FUNCTION from_sql_to_client (Address_t)
      RETURNS VARCHAR (150)
      LANGUAGE C
      TRANSFORM GROUP func_group
      EXTERNAL NAME 'addressudf!address_from_sql_to_client'
      NOT VARIANT
      NO EXTERNAL ACTION
      NOT FENCED
      NO SQL
      PARAMETER STYLE DB2SQL;

前述の例の DDL では、from_sql_to_client UDF が、タイプ Address_t のパラメーターを受け入れるかのように示されています。実際には、from_sql_to_client UDF が呼び出されるそれぞれの行のために、 Addresstofunc transform が Address をさまざまな属性に分解します。 from_sql_to_client UDF は、単純な文字ストリングを生成し、住所属性を表示できるように形式設定するので、次の単純な SQL 照会を使用して、 Person 表のそれぞれの行の Name および Address 属性を表示することができます。

   SELECT Name, from_sql_to_client (Address)
   FROM Person;

クライアントからのバインドインのための client transform

次の DDL は、クライアントからの VARCHAR で符号化されたオブジェクトを受け取る関数を登録し、それをさまざまな基本タイプ属性に分解して、TO SQL function transform に渡します。

   CREATE FUNCTION to_sql_from_client (VARCHAR (150))
      RETURNS Address_t
      LANGUAGE C
      TRANSFORM GROUP func_group
      EXTERNAL NAME 'addressudf!address_to_sql_from_client'
      NOT VARIANT
      NO EXTERNAL ACTION
      NOT FENCED
      NO SQL
      PARAMETER STYLE DB2SQL;

to_sql_from_client が住所を直接戻すように見えますが、実際には、to_sql_from_client が VARCHAR (150) を基本タイプ属性のセットに変換します。その後で、DB2 は明示的に TO SQL transform functoaddress を呼び出して、データベースに戻される住所オブジェクトを構成します。

呼び出す function transform を DB2 に知らせる方法 to_sql_from_clientfrom_sql_to_client の両方の DDL に、 TRANSFORM GROUP という文節が入っていることに注意してください。この文節は、これらの関数の中の住所タイプを処理するために、どの transform のセットを使用するかを DB2 に伝えています。詳細については、transform のタイプとの関連付けを参照してください。

データ変換についての考慮事項

サーバーとクライアントとの間でデータ、特にバイナリー・データが交換される時は、考慮すべきデータ変換の問題がいくつかあることを覚えておいてください。たとえば、バイト順序づけ体系が異なるプラットフォーム間でデータが転送される時は、正しい数値を復元するために、数値データに対してバイト逆転処理を行う必要があります。異なるオペレーティング・システムでは、メモリー内の数値データを参照するための一定の調整要件も異なります。つまり、これらの要件が満たされていないと、プログラム例外が発生するオペレーティング・システムもあるということです。文字データが BLOB または VARCHAR FOR BIT DATA などのバイナリー・データの中に組み込まれていなければ、文字データ・タイプは、データベースによって自動的に変換されます。

データ変換の問題を避けるには、次の 2 とおりの方法があります。

注:サーバーとクライアントとの間のデータの転送に関連した複雑な問題を transform 関数が正しく処理できるよう、 transform 関数は可能な限り開発者が作成すべきです。アプリケーションを設計する時は、現在の環境の特定の要件を考慮し、完全な汎用性と単純性との間でのトレードオフを評価してください。たとえば、データベース・サーバーとそのすべてのクライアントは、両方とも AIX 環境で稼働し、同じコード・ページを使用することが分かっている場合は、現在必要な変換は何もないので、前述の考慮事項は無視することができます。しかし、将来環境が変わる場合は、データ変換を正しく処理するよう元の設計を修正するのに、相当の努力を払わなければならなくなります。

transform 関数の要約

表 15 は、外部ルーチンまたはクライアント・アプリケーションにバインドアウトするかどうかに基づいて、必要な transform 関数が何であるかを決定するのに役立ちます。

表 15. transform 関数の特性
特性 外部ルーチンとの値の交換 クライアント・アプリケーションとの値の交換
transform の方向 FROM SQL TO SQL FROM SQL TO SQL
変換される対象 ルーチン・パラメーター ルーチン結果 出力ホスト変数 入力ホスト変数
振る舞い 分解 構成 符号化 復号
transform 関数のパラメーター 構造型 組み込みタイプの行 構造型 1 つの組み込みタイプ
transform 関数の結果 組み込みタイプの行 (おそらくは属性) 構造型 1 つの組み込みタイプ 構造型
別の transform への依存性 なし なし FROM SQL UDF transform TO SQL UDF transform
transform グループが指定される時期 UDF が登録される時
静的: プリコンパイル時
動的: 特殊レジスター

データ変換についての考慮事項の有無 なし あり
注:一般的な事例ではありませんが、次のどちらかが真である場合は、クライアント・タイプの transform は、実際に SQL で作成できます。
  • 構造型に 1 つの属性しかない場合。
  • 組み込みタイプへの属性の符号化および複号が、 SQL 演算子または関数がいくつか組み合わされることによって行われる。

このような場合は、構造型の値をクライアント・アプリケーションと交換するために、 function transform に依存する必要はありません。

サブタイプ・データの DB2 からの検索 (バインドアウト)

前述のセクションのほとんどの情報は、アプリケーションが既知の正確なタイプを渡しているということを前提としています。データ・モデルがサブタイプを利用する場合は、列の中の値は、さまざまなサブタイプのうちのいずれかになります。このセクションでは、実際の入力タイプに基づいて、正しい transform 関数を動的に選択する方法を説明します。

次の SELECT ステートメントを発行するとします。

   SELECT Address
      FROM Person
      INTO :hvaddr;

アプリケーションには、Address_tUS_addr_t などのインスタンスが戻されるかどうかはまったく分かりません。この例を複雑なものにしないように、 Address_tUS_addr_t だけが戻されると想定しましょう。これらの構造は異なっているので、属性を分解する transform も異なっていなければなりません。正しい transform が呼び出されるようにするために、次のステップを実行します。

ステップ 1.

住所のすべてのバリエーションのための FROM SQL function transform を作成する。

   CREATE FUNCTION addresstofunc(A address_t)
      RETURNS ROW
      (Street VARCHAR(30), Number CHAR(15), City
      VARCHAR(30), STATE VARCHAR (10))
      LANGUAGE SQL
      RETURN VALUES
      (A..Street, A..Number, A..City, A..State)
   CREATE FUNCTION US_addresstofunc(A US_addr_t)
      RETURNS ROW
      (Street VARCHAR(30), Number CHAR(15), City
      VARCHAR(30), STATE VARCHAR (10), Zip
      CHAR(10))
      LANGUAGE SQL
      RETURN VALUES
      (A..Street, A..Number, A..City, A..State, A..Zip)

ステップ 2.

それぞれのタイプ・バリエーションにつき 1 つの transform グループを作成する。

   CREATE TRANSFORM FOR Address_t
      funcgroup1 (FROM SQL WITH FUNCTION addresstofunc)
   CREATE TRANSFORM FOR US_addr_t
      funcgroup2 (FROM SQL WITH FUNCTION US_addresstofunc)

ステップ 3.

それぞれのタイプ・バリエーションにつき 1 つの外部 UDF を作成する。

Address_t タイプのための外部 UDF を登録する。

   CREATE FUNCTION address_to_client (A Address_t)
      RETURNS VARCHAR(150)
      LANGUAGE C
      EXTERNAL NAME 'addressudf!address_to_client'
      ...
      TRANSFORM GROUP funcgroup1

address_to_client UDF を作成する。

   void SQL_API_FN address_to_client(
      SQLUDF_VARCHAR *street,
      SQLUDF_CHAR    *number,
      SQLUDF_VARCHAR *city,
      SQLUDF_VARCHAR *state,
      SQLUDF_VARCHAR *output,
      /* Null indicators for attributes */
      SQLUDF_NULLIND *street_ind,
      SQLUDF_NULLIND *number_ind,
      SQLUDF_NULLIND *city_ind,
      SQLUDF_NULLIND *state_ind,
      /* Null indicator for instance */
      SQLUDF_NULLIND *address_ind,
      /* Null indicator for output */
      SQLUDF_NULLIND *output_ind,
      SQLUDF_TRAIL_ARGS)
   {
      sprintf (output, "[address_t] [Street:%s] [number:%s]
      [city:%s] [state:%s]",
      street, number, city, state);
      *output_ind = 0;
   }

US_addr_t タイプのための外部 UDF を登録する。

   CREATE FUNCTION address_to_client (A US_addr_t)
      RETURNS VARCHAR(150)
      LANGUAGE C
      EXTERNAL NAME 'addressudf!US_addr_to_client'
      ...
      TRANSFORM GROUP funcgroup2

US_addr_to_client UDF を作成する。

   void SQL_API_FN US_address_to_client(
      SQLUDF_VARCHAR  *street,
      SQLUDF_CHAR     *number,
      SQLUDF_VARCHAR  *city,
      SQLUDF_VARCHAR  *state,
      SQLUDF_CHAR     *zip,
      SQLUDF_VARCHAR  *output,
      /* Null indicators */
      SQLUDF_NULLIND  *street_ind,
      SQLUDF_NULLIND  *number_ind,
      SQLUDF_NULLIND  *city_ind,
      SQLUDF_NULLIND  *state_ind,
      SQLUDF_NULLIND  *zip_ind,
      SQLUDF_NULLIND  *us_address_ind,
      SQLUDF_NULLIND  *output_ind,
      SQLUDF_TRAIL_ARGS)
   {
      sprintf (output, "[US_addr_t] [Street:%s] [number:%s]
      [city:%s] [state:%s] [zip:%s]",
      street, number, city, state, zip);
      *output_ind = 0;
   }

ステップ 4.

インスタンスを処理するための正しい外部 UDF を選択する、SQL を本体として持つ UDF を作成する。次の UDF は、UNION ALL 文節で結合された SELECT ステートメントに TREAT を指定して、正しい FROM SQL transform を呼び出します。

   CREATE FUNCTION addr_stream (ab Address_t)
      RETURNS VARCHAR(150)
      LANGUAGE SQL
      RETURN
      WITH temp(addr) AS
      (SELECT address_to_client(ta.a)
         FROM TABLE (VALUES (ab)) AS ta(a)
         WHERE ta.a IS OF (ONLY Address_t)
         UNION ALL
      SELECT address_to_client(TREAT (tb.a AS US_addr_t))
         FROM TABLE (VALUES (ab)) AS tb(a)
         WHERE tb.a IS OF (ONLY US_addr_t))
      SELECT addr FROM temp;

これで、アプリケーションは、 Addr_stream 関数を呼び出して、ふさわしい外部 UDF を呼び出すことができます。

   SELECT Addr_stream(Address)
      FROM Employee;

ステップ 5.

Addr_stream 外部 UDF を、 Address_t のための FROM SQL client transform として追加する。

   CREATE TRANSFORM GROUP FOR Address_t
      client_group (FROM SQL
      WITH FUNCTION Addr_stream)

注:アプリケーションが、タイプ述部を使用して照会の中で特定の住所を指定する場合は、 Addr_stream を FROM SQL として US_addr_t のための client transform に追加します。これで、照会が US_addr_t のインスタンスを明確に要求する時に、 Addr_stream を呼び出すことができるようになります。

ステップ 6.

TRANSFORM GROUP オプションを client_group に設定して、アプリケーションをバインドする。

   PREP myprogram TRANSFORM GROUP client_group

DB2 が SELECT Address FROM Person INTO :hvar ステートメントを含むアプリケーションをバインドする時は、 DB2 は FROM SQL client transform を探します。 DB2 は、構造型がバインドアウトされていることを認識し、 transform グループ client_group の中を探します。なぜなら、これは 6 でバインド実行時に指定された TRANSFORM GROUP であるからです。

transform グループには、 5 のルート・タイプ Address_t に関連した transform 関数 Addr_stream が入っています。 Addr_stream は、 4 で定義されている SQL を本体として持つ関数なので、これは他の transform 関数とは従属関係を持っていません。 Addr_stream 関数は、 :hvaddr ホスト変数が要求するデータ・タイプ VARCHAR(150) を戻します。

Addr_stream 関数は、タイプ Address_t (この例では US_addr_t で代用できる) の入力値を取り、入力値の動的タイプを決定します。動的タイプを決定する時に Addr_stream は、動的タイプが Address_t である場合は、 address_to_client という値に対して、動的タイプが US_addr_t である場合は、 USaddr_to_client という値に対して、対応する外部 UDF を発行します。これら 2 つの UDF は、3 で定義されています。これらの UDF は両方とも、それぞれの構造型を、 Addr_stream transform 関数が要求するタイプである VARCHAR(150) に分解します。

構造型を入力として受け入れるために、それぞれの UDF には、入力構造型インスタンスを個々の属性パラメーターに分解するための FROM SQL transform 関数が必要です。 3 の CREATE FUNCTION ステートメントは、これらの transform が入っている TRANSFORM GROUP に名前を付けています。

transform 関数のための CREATE FUNCTION ステートメントは、 1 で発行されています。 transform 関数を transform グループと関連付ける CREATE TRANSFORM ステートメントは、 2 で発行されています。

サブタイプ・データを DB2 に戻す (バインドイン)

サブタイプ・データの DB2 からの検索 (バインドアウト) で説明されているアプリケーションが住所の値を操作すると、そのアプリケーションは変更された値をデータベースに挿入する必要があります。次の構文を使用して、構造型をアプリケーションから DB2 データベースに挿入するとします。

   INSERT INTO person (Oid, Name, Address)
      VALUES ('n', 'Norm', :hvaddr);

構造型のための INSERT ステートメントを実行するには、アプリケーションは次のステップを実行する必要があります。

ステップ 1.

住所のすべてのバリエーションのための TO SQL function transform を作成する。次の例は、Address_t および US_addr_t タイプを変換する、 SQL を本体としてもつ UDF を示しています。

   CREATE FUNCTION functoaddress
    (str VARCHAR(30), num CHAR(15), cy VARCHAR(30), st VARCHAR (10))
   RETURNS Address_t
   LANGUAGE SQL
   RETURN Address_t()..street(str)..number(num)..city(cy)..state(st);
   CREATE FUNCTION functoaddress
    (str VARCHAR(30), num CHAR(15), cy VARCHAR(30), st VARCHAR (10),
     zp CHAR(10))
   RETURNS US_addr_t
   LANGUAGE SQL
   RETURN US_addr_t()..street(str)..number(num)..city(cy)
       ..state(st)..zip(zp);

ステップ 2.

それぞれのタイプ・バリエーションにつき 1 つの transform グループを作成する。

   CREATE TRANSFORM FOR Address_t
      funcgroup1 (TO SQL
      WITH FUNCTION functoaddress);
   CREATE TRANSFORM FOR US_addr_t
      funcgroup2 (TO SQL
      WITH FUNCTION functousaddr);

ステップ 3.

それぞれのタイプ・バリエーションにつき 1 つの符号化された住所タイプを戻す外部 UDF を作成する。

Address_t タイプのための外部 UDF を登録する。

   CREATE FUNCTION client_to_address (encoding VARCHAR(150))
      RETURNS Address_t
      LANGUAGE C
      TRANSFORM GROUP funcgroup1
      ...
      EXTERNAL NAME 'address!client_to_address';

client_to_addressAddress_t バージョンのための外部 UDF を作成する。

   void SQL_API_FN client_to_address (
      SQLUDF_VARCHAR *encoding,
      SQLUDF_VARCHAR *street,
      SQLUDF_CHAR    *number,
      SQLUDF_VARCHAR *city,
      SQLUDF_VARCHAR *state,
      /* Null indicators */
      SQLUDF_NULLIND *encoding_ind,
      SQLUDF_NULLIND *street_ind,
      SQLUDF_NULLIND *number_ind,
      SQLUDF_NULLIND *city_ind,
      SQLUDF_NULLIND *state_ind,
      SQLUDF_NULLIND *address_ind,
      SQLUDF_TRAIL_ARGS )
   {
      char c[150];
      char *pc;
      strcpy(c, encoding);
      pc = strtok (c, ":]");
      pc = strtok (NULL, ":]");
      pc = strtok (NULL, ":]");
      strcpy (street, pc);
      pc = strtok (NULL, ":]");
      pc = strtok (NULL, ":]");
      strcpy (number, pc);
      pc = strtok (NULL, ":]");
      pc = strtok (NULL, ":]");
      strcpy (city, pc);
      pc = strtok (NULL, ":]");
      pc = strtok (NULL, ":]");
      strcpy (state, pc);
      *street_ind = *number_ind = *city_ind
      = *state_ind = *address_ind = 0;
   }

US_addr_t タイプのための外部 UDF を登録する。

   CREATE FUNCTION client_to_us_address (encoding VARCHAR(150))
      RETURNS US_addr_t
      LANGUAGE C
      TRANSFORM GROUP funcgroup1
      ...
      EXTERNAL NAME 'address!client_to_US_addr';

client_to_addressUS_addr_t バージョンのための外部 UDF を作成する。

   void SQL_API_FN client_to_US_addr(
      SQLUDF_VARCHAR *encoding,
      SQLUDF_VARCHAR *street,
      SQLUDF_CHAR    *number,
      SQLUDF_VARCHAR *city,
      SQLUDF_VARCHAR *state,
      SQLUDF_VARCHAR *zip,
      /* Null indicators */
      SQLUDF_NULLIND *encoding_ind,
      SQLUDF_NULLIND *street_ind,
      SQLUDF_NULLIND *number_ind,
      SQLUDF_NULLIND *city_ind,
      SQLUDF_NULLIND *state_ind,
      SQLUDF_NULLIND *zip_ind,
      SQLUDF_NULLIND *us_addr_ind,
      SQLUDF_TRAIL_ARGS)
   {
      char c[150];
      char *pc;
      strcpy(c, encoding);
      pc = strtok (c, ":]");
      pc = strtok (NULL, ":]");
      pc = strtok (NULL, ":]");
      strcpy (street, pc);
      pc = strtok (NULL, ":]");
      pc = strtok (NULL, ":]");
      strncpy (number, pc,14);
      pc = strtok (NULL, ":]");
      pc = strtok (NULL, ":]");
      strcpy (city, pc);
      pc = strtok (NULL, ":]");
      pc = strtok (NULL, ":]");
      strcpy (state, pc);
      pc = strtok (NULL, ":]");
      pc = strtok (NULL, ":]");
      strncpy (zip, pc, 9);
      *street_ind = *number_ind = *city_ind
      = *state_ind = *zip_ind = *us_addr_ind = 0;
   }

ステップ 4.

インスタンスを処理するための正しい外部 UDF を選択する、SQL を本体として持つ UDF を作成する。次の UDF は、UNION ALL 文節で結合された SELECT ステートメントに TREAT を指定して、正しい FROM SQL transform を呼び出します。結果は、一時表に置かれます。

   CREATE FUNCTION stream_address (ENCODING VARCHAR(150))
      RETURNS Address_t
      LANGUAGE SQL
      RETURN
      (CASE(SUBSTR(ENCODING,2,POSSTR(ENCODING,']')-2))
      WHEN 'address_t'
         THEN client_to_address(ENCODING)
      WHEN 'us_addr_t'
         THEN client_to_us_addr(ENCODING)
      ELSE NULL
      END);

ステップ 5.

stream_address UDF を、 Address_t のための TO SQL client transform として追加する。

   CREATE TRANSFORM FOR Address_t
      client_group (TO SQL
      WITH FUNCTION stream_address);

ステップ 6.

TRANSFORM GROUP オプションを client_group に設定して、アプリケーションをバインドする。

   PREP myProgram2 TRANSFORM GROUP client_group

構造型がバインドされた INSERT ステートメントが、アプリケーションに含まれている時は、 DB2 は TO SQL client transform を探します。 DB2 は、transform グループ client_group の中でこの transform を探します。なぜなら、これは 6 でバインド実行時に指定された TRANSFORM GROUP であるからです。 DB2 は、必要とする transform 関数 stream_address を検出します。これは 5 で、ルート・タイプ Address_t と関連付けられています。

stream_address は、 4 で定義されている SQL を本体として持つ関数なので、これは追加の transform 関数とは明示された従属関係を持っていません。入力パラメーターについては、 stream_address は VARCHAR(150) を受け入れます。これはアプリケーション・ホスト変数 :hvaddr に対応するものです。 stream_address は、正しいルート・タイプ Address_t の値であり、正しい動的タイプの値でもある値を戻します。

stream_address は、 VARCHAR(150) 入力パラメーターを解析して、動的タイプ (この事例では、 'Address_t' か 'US_addr_t' のいずれか) を指定するサブストリングを探します。次に stream_address は、対応する外部 UDF を発行して、 VARCHAR(150) を解析し、指定のタイプのオブジェクトを戻します。それぞれのタイプを戻す 2 つの client_to_address() UDF があります。これらの UDF は、3 で定義されています。それぞれの UDF は入力 VARCHAR(150) を取り、ふさわしい構造型の属性を内部的に構成し、このようにして構造型を戻します。

構造型を戻すために、それぞれの UDF には、出力属性値を構造型のインスタンスに構成するための TO SQL transform 関数が必要です。 3 の CREATE FUNCTION ステートメントは、 transform が入っている TRANSFORM GROUP に名前を付けています。

1 の SQL を本体として持つ transform 関数と、 2 の transform グループとの関連は、 3 の CREATE FUNCTION ステートメントの中で指定されています。

構造型ホスト変数の処理

構造型ホスト変数の宣言

静的 SQL の中の構造型ホスト変数を検索または送信するには、その構造型を表すのに使用される組み込みタイプを指示する SQL 宣言を提供する必要があります。この宣言の形式は次のとおりです。

   EXEC SQL BEGIN DECLARE SECTION ;
      SQL TYPE IS structured_type AS base_type host-variable-name ;
   EXEC SQL END DECLARE SECTION;

たとえば、タイプ Address_t は、クライアント・アプリケーションに渡される時に、可変長文字タイプに変換されるとしましょう。 Address_t タイプのホスト変数には、次の宣言を使用します。

   SQL TYPE IS Address_t AS VARCHAR(150) addrhv;

構造型の記述

構造型変数を指定した DESCRIBE ステートメントを使用すると、 FROM SQL transform 関数の結果タイプの記述が、 DB2 によって SQLDA の基本 SQLVAR の SQLTYPE フィールドに入れられます。しかし、CURRENT DEFAULT TRANSFORM GROUP 特殊レジスターを使用して TRANSFORM GROUP が指定されていないか、指定したグループに FROM SQL transform 関数が定義されていないというどちらかの理由で、 FROM SQL transform 関数が定義されていない場合は、DESCRIBE はエラーを戻します。

構造型の実際の名前は、SQLVAR2 の中に戻されます。 SQLDA の構造の詳細については、SQL 解説書 を参照してください。


[ ページのトップ | 前ページ | 次ページ | 目次 | 索引 ]