ヘッダーをスキップ
Oracle® Database SecureFilesおよびラージ・オブジェクト開発者ガイド
11gリリース2 (11.2)
B56263-04
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

20 永続LOB用のデータ・インタフェース

この章の内容は次のとおりです。

永続LOB用のデータ・インタフェースの概要

永続LOB用のデータ・インタフェースには、LOBデータ型を処理するように拡張された一連のJava API、PL/SQL APIおよびOCI APIが組み込まれています。これらのAPIは、当初はLONGLONG RAWおよびVARCHAR2などのレガシー・データ型用に設計されましたが、表20-1表20-2に示す対応するLOBデータ型にも使用できます。この2つの表で、「バインド型または定義型」列はレガシー・データ型を示し、「LOB列の型」列は対応するサポート対象のLOBデータ型を示します。LOB用のデータ・インタフェースを使用すると、対応するレガシー・データ型に格納されている場合と同様に、文字データとバイナリ・データをLOB列に格納して操作できます。


注意:

データ・インタフェースは、オブジェクトの属性であるLOBのみでなくLOB列に対しても機能します。この章では、「LOB列」とはLOB列およびLOB属性を意味します。

配列のバインドおよび定義インタフェースを使用すると、複数の行を1回のラウンドトリップで挿入および選択できます。


簡潔にするために、この章では文字データ型を中心に説明しますが、表20-1表20-2に示す文字データ型とバイナリ・データ型のフル・セットにも同じ概念が適用されます。これらの表では、CLOBNCLOBも意味しています。

表20-1 SQLとPL/SQLでの対応するLONGデータ型とLOBデータ型

バインド型または定義型 LOB列の型 格納するデータ

CHAR

CLOB

文字データ

LONG

CLOB

文字データ

VARCHAR2

CLOB

文字データ

LONG RAW

BLOB

バイナリ・データ

RAW

BLOB

バイナリ・データ


表20-2 OCIでの対応するLONGデータ型とLOBデータ型

バインド型または定義型 LOB列の型 格納するデータ

SQLT_AFC(n)

CLOB

文字データ

SQLT_CHR

CLOB

文字データ

SQLT_LNG

CLOB

文字データ

SQLT_VCS

CLOB

文字データ

SQLT_BIN

BLOB

バイナリ・データ

SQLT_LBI

BLOB

バイナリ・データ

SQLT_LVB

BLOB

バイナリ・データ


永続LOB用のデータ・インタフェースを使用するメリット

永続LOB用のデータ・インタフェースを使用すると、次のメリットがあります。

  • アプリケーションでLONGデータ型を使用する場合は、既存のアプリケーションへの変更をまったく、またはほとんど必要とせずにLOBデータ型で同じアプリケーションを使用できます。そのためには、第18章「LONGからLOBへの列の移行」で説明しているように、単に表のLONGデータ型列をLOBデータ型列に変換します。

  • 逐次アクセス技法を使用するOCIアプリケーションの場合は、パフォーマンスが向上します。データ・インタフェースを使用してピース単位のINSERTまたはフェッチを実行すると、OCILobRead2()OCILobWrite2()などのOCI関数を使用する場合と同様のパフォーマンスが得られます。データ・インタフェースを使用すると、1回のOCIコールでLOBに4KBを超えるデータを挿入できるため、サーバーへのラウンドトリップを削減できます。

  • 最初にLOBロケータをフェッチしてからOCILobRead2()をコールするかわりに、1回のOCIStmtFetch()コールでLOBデータを読み取ることができます。これにより、LOBデータを最初から読み取る場合のパフォーマンスが向上します。

  • 配列のバインドおよび定義インタフェースを使用すると、LOBを含む複数の行を1回のラウンドトリップで挿入および選択できます。

PL/SQLにおける永続LOB用のデータ・インタフェースの使用

このデータ・インタフェースを使用すると、表20-1に示すLONGデータ型とLOBデータ型を使用して、PL/SQLで次の操作を実行できます。

  • VARCHAR2CHARまたはLONGなどのデータ型で格納された文字データをCLOB列にINSERTまたはUPDATEします。

  • RAWまたはLONG RAWなどのデータ型で格納されたバイナリ・データをBLOB列にINSERTまたはUPDATEします。

  • CLOB列でSELECT文を使用して、データをCHARLONGまたはVARCHAR2などの文字バッファ変数に選択します。

  • BLOB列でSELECT文を使用して、データをRAWLONG RAWなどのバイナリ・バッファ変数に選択します。

  • CLOBVARCHAR2CHARまたはLONG変数の間で型間の割当て(暗黙的な型変換)を実行します。

  • BLOBRAWまたはLONG RAW変数の間で型間の割当て(暗黙的な型変換)を実行します。

  • LONGデータ型を受け入れるように定義されたファンクションにLOBデータ型を渡すか、LOBデータ型を受け入れるように定義されたファンクションにLONGデータ型を渡します。たとえば、VARCHAR2CHARまたはLONGなど、他のキャラクタ・タイプを受け入れるように定義されたファンクションに、CLOBインスタンスを渡すことができます。

  • INSTRSUBSTRなどのVARCHAR2引数を受け入れる他のPL/SQLファンクションおよび演算子とともにCLOBを使用します。詳細なリストは、「SQLおよびPL/SQL組込みファンクションへのCLOBの受渡し」を参照してください。


    注意:

    PL/SQLでLOB用のデータ・インタフェースをSELECT文とともに使用する場合、読み取る量は指定できません。指定できるのは、バッファ長のみです。バッファ長がLOBデータより短い場合は、データベースで例外が発生します。


    関連項目:


SQLとPL/SQLでデータ・インタフェースを使用してLOB列にアクセスする際のガイドライン

この項では、永続LOB用のデータ・インタフェースを使用してLOB列またはLOB属性にアクセスする方法について説明します。

CLOBおよびBLOB列または属性からのデータは、INSERTUPDATESELECTなどの通常のSQL文によって参照できます。

PL/SQLには、ピース単位のINSERTUPDATEまたはフェッチ用のルーチンがありません。そのため、LOB列またはLOB属性からアクセスできるデータ量は、文字バッファ・サイズの最大値によって制限されます。PL/SQLは文字バッファ・サイズを32KB - 1(32767バイト)までサポートします。このため、PL/SQLアプリケーションで永続LOB用のデータ・インタフェースを使用してアクセスできるLOBは、32KB未満に制限されます。

データ・インタフェースを使用して32KB - 1を超えるデータにアクセスする場合は、PL/SQLコードからOCIコールを実行して、ピース単位挿入およびフェッチ用のAPIを使用する必要があります。

データ・インタフェースを使用してLOB列またはLOB属性にアクセスする場合は、次のガイドラインに従ってください。

  • INSERT操作

    VALUES句の通常のINSERT文を使用して、LOB列またはLOB属性を含む表にINSERTできます。LOB列のフィールドは、リテラル、文字データ型、バイナリ・データ型またはLOBロケータです。

  • UPDATE操作

    LOB列またはLOB属性は、UPDATE... SET文によって全体を更新できます。SET句では、新しい値にリテラル、文字データ型、バイナリ・データ型またはLOBロケータを使用できます。

  • 16進からRAWおよびRAWから16進への変換に関する4000バイトの制限

    サイズが4000バイトを超えるデータの場合、データベースでは16進からRAWまたはRAWから16進への暗黙的な変換は実行されません。バッファのサイズが4000バイトを超える場合、文字データのバッファはバイナリ・データ型の列にバインドできず、バイナリ・データのバッファは文字データ型の列にバインドできません。この種のバインドを試みると、列データが4000バイトで切り捨てられます。

    たとえば、サイズが4000バイトを超えるVARCHAR2バッファはLONG RAW列またはBLOB列にバインドできません。同様に、サイズが4000バイトを超えるRAWバッファはLONG列またはCLOB列にバインドできません。

  • SELECT操作

    PL/SQLでは、LOB列またはLOB属性を選択して文字バッファまたはバイナリ・バッファに格納できます。LOB列またはLOB属性がバッファ・サイズより大きい場合、データはバッファに格納されず、例外が発生します。LOB列またはLOB属性は、LOBロケータとしても選択できます。

暗黙的な割当ておよびパラメータの受渡し

LOB列の場合は、暗黙的な割当てとパラメータの受渡しがサポートされます。表20-1および表20-2に示したデータ型の場合は、永続LOB用のデータ・インタフェースを使用して、キャラクタ・タイプを別のキャラクタ・タイプに、またはバイナリ型を他のバイナリ型に渡したり割り当てることができます。

暗黙的な割当ては、次の例に示すように、明示的に宣言された変数と、%TYPE属性を使用して既存の列の型を参照することで宣言された変数に対して機能します。この例では、t表のlong_col列がLONGからCLOB列に移行されたものとします。

CREATE TABLE t (long_col LONG); -- Alter this table to change LONG column to LOB
DECLARE
   a VARCHAR2(100);
   b t.long_col%type; -- This variable changes from LONG to CLOB
BEGIN
   SELECT * INTO b FROM t;
   a := b;  -- This changes from "VARCHAR2 := LONG to VARCHAR2 := CLOB
   b := a;  -- This changes from "LONG := VARCHAR2 to CLOB := VARCHAR2 
END;

ファンクションとプロシージャの間で暗黙的なパラメータの受渡しが可能です。たとえば、仮パラメータがVARCHAR2として定義されているファンクションまたはプロシージャにCLOBを渡すことができます。


注意:

LOB変数にVARCHAR2バッファを割り当てると、VARCHAR2LONG変数に割り当てるより効率が悪くなります。これは、前者で一時LOBの作成が伴うためです。したがって、PL/SQLユーザーは、アプリケーションで若干のパフォーマンス低下を感じます。

SQLおよびPL/SQL組込みファンクションへのCLOBの受渡し

暗黙的なパラメータの受渡しは、文字データを受け入れるPL/SQL組込みファンクションの場合もサポートされます。たとえば、INSTRには、他の文字データのみでなくCLOBも使用できます。

VARCHAR2を受け入れるSQLまたはPL/SQL組込みファンクションは、すべて引数としてCLOBを受け入れることができます。同様に、LOBロケータを取るパラメータについては、どのDBMS_LOB APIにもVARCHAR2変数を渡すことができます。

明示的な変換ファンクション

PL/SQLでは、次の明示的な変換ファンクションにより、他のデータ型がCLOBおよびBLOBデータ型に変換されます。

  • TO_CLOB()は、LONGVARCHAR2およびCHARCLOBに変換します。

  • TO_BLOB()は、LONG RAWおよびRAWBLOBに変換します。

変換ファンクションTO_CHAR()CLOBCHAR型に変換できることにも注意してください。

SQLからのPL/SQLプロシージャおよびCプロシージャのコール

SQLからPL/SQLプロシージャまたはCプロシージャをコールする場合、4000バイトを超えるデータを含むバッファは許可されません。

PL/SQLからのPL/SQLプロシージャおよびCプロシージャのコール

PL/SQLまたはCのプロシージャをPL/SQLからコールできます。CHRを仮パラメータ、CLOBを実パラメータとして渡すことも、その逆も可能です。BLOBRAWについても、これは同様です。

これにはどのような場合があるかというと、たとえば、仮パラメータまたは実パラメータがアンカー型の場合、つまり変数がtable_name.column_name%type構文を使用して宣言されている場合です。

PL/SQLプロシージャまたはファンクションには、CLOBまたはVARCHAR2を仮パラメータとして指定できます。たとえば、PL/SQLプロシージャは次のいずれかのように指定できます。

  • 仮パラメータがCLOBの場合:

    CREATE OR REPLACE PROCEDURE get_lob(table_name IN VARCHAR2, lob INOUT
    CLOB) AS
       ...
    BEGIN
      ...
    END;
    /
    
  • 仮パラメータがVARCHAR2の場合:

    CREATE OR REPLACE PROCEDURE get_lob(table_name IN VARCHAR2, lob INOUT
    VARCHAR2) AS
       ...
    BEGIN
      ...
    END;
    /
    

コールするファンクションは次のいずれかのタイプです。

  • 実パラメータがCHRの場合:

    create procedure ...
    declare 
    c VARCHAR2[200];
    BEGIN
      get_lob('table_name', c);
    END;
     
    
  • 実パラメータがCLOBの場合:

    create procedure ...
    declare 
    c CLOB; 
    BEGIN
      get_lob('table_name', c);
    END;
    

INSERT操作とUPDATE操作でのすべてのサイズのバインド

LOB列に対するINSERT操作とUPDATE操作では、すべてのサイズのバインドがサポートされます。1つのINSERT文またはUPDATE文で、任意のサイズの複数のバインドが可能です。


注意:

表の作成時には、LOB列のデフォルト値に指定できる長さが4000バイトに制限されています。

SQL演算子の結果に対する4000バイトの制限

4000バイトを超えるデータをBLOBまたはCLOBにバインドし、そのデータがSQL演算子で構成される場合、結果のサイズは最大4000バイトに制限されます。

次の文では、LPADの結果が4000バイトに制限されているため、4000バイトのみ挿入されます。

INSERT INTO print_media (ad_sourcetext) VALUES (lpad('a', 5000, 'a'));

次の文は2000バイトしか挿入しません。LPADの結果は4000バイトに制限されており、16進からRAWへ暗黙的に変換すると、RAWデータの2000バイトが変換されるためです。

INSERT INTO print_media (ad_photo) VALUES (lpad('a', 5000, 'a'));  

SQL演算子の結果に対する4000バイトの制限の例

次の例に、SQL演算子の結果が4000バイトに制限されることを示します。

/* The following command inserts only 4000 bytes because the result of
 * LPAD is limited to 4000 bytes */
INSERT INTO print_media(product_id, ad_id, ad_sourcetext)
  VALUES (2004, 5, lpad('a', 5000, 'a'));
SELECT LENGTH(ad_sourcetext) FROM print_media 
  WHERE product_id=2004 AND ad_id=5;
ROLLBACK;

/* The following command inserts only 2000 bytes because the result of
 * LPAD is limited to 4000 bytes, and the implicit hex to raw conversion
 * converts it to 2000 bytes of RAW data. */
INSERT INTO print_media(product_id, ad_id, ad_composite)
  VALUES (2004, 5, lpad('a', 5000, 'a'));
SELECT LENGTH(ad_composite) from print_media 
  WHERE product_id=2004 AND ad_id=5;
ROLLBAACK;

4000バイトを超えるバインドに対する制限

4000バイトを超えるバインドに対する制限事項を次に示します。

  • 表にLONG列とLOB列の両方がある場合、LONG列またはLOB列のいずれかに4000バイトを超えるデータをバインドできますが、同一の文で両方にバインドすることはできません。

  • INSERT AS SELECT操作では、どのような長さのデータもLOB列にバインドできません。

LOBに対するパラレルDMLのサポート

LOB列を含む表に対する次のDML操作のパラレル実行がサポートされています。これらの操作がパラレル実行モードで実行されるのは、パーティション表に対して実行する場合のみです。LOB列を含む非パーティション表のDML文は、引き続きシリアル実行モードで実行されます。

  • INSERT AS SELECT

  • CREATETABLEASSELECT

  • DELETE

  • UPDATE

  • MERGE(条件付きUPDATEおよびINSERT)

  • 複数表INSERT


関連項目:

『Oracle Database管理者ガイド』のパラレルSQL実行プロセスの管理に関する項を参照してください。

例: PL/SQL: INSERTおよびUPDATEでの4000バイトを超えるバインドの使用

DECLARE
  bigtext VARCHAR2(32767);
  smalltext VARCHAR2(2000);
  bigraw RAW (32767);
BEGIN
  bigtext := LPAD('a', 32767, 'a');
  smalltext := LPAD('a', 2000, 'a');
  bigraw := utl_raw.cast_to_raw (bigtext);

  /* Multiple long binds for LOB columns are allowed for INSERT: */
  INSERT INTO print_media(product_id, ad_id, ad_sourcetext, ad_composite)
    VALUES (2004, 1, bigtext, bigraw);

  /* Single long bind for LOB columns is allowed for INSERT: */
  INSERT INTO print_media (product_id, ad_id, ad_sourcetext)
    VALUES (2005, 2, smalltext);  

  bigtext := LPAD('b', 32767, 'b');
  smalltext := LPAD('b', 20, 'a');
  bigraw := utl_raw.cast_to_raw (bigtext);

  /* Multiple long binds for LOB columns are allowed for UPDATE: */
  UPDATE print_media SET ad_sourcetext = bigtext, ad_composite = bigraw,
    ad_finaltext = smalltext;

  /* Single long bind for LOB columns is allowed for UPDATE: */
  UPDATE print_media SET ad_sourcetext = smalltext, ad_finaltext = bigtext;

  /* The following is NOT allowed because we are trying to insert more than
     4000 bytes of data in a LONG and a LOB column: */
  INSERT INTO print_media(product_id, ad_id, ad_sourcetext, press_release)
    VALUES (2030, 3, bigtext, bigtext);
  
  /* Insert of data into LOB attribute is allowed */
  INSERT INTO print_media(product_id, ad_id, ad_header)
     VALUES (2049, 4, adheader_typ(null, null, null, bigraw));

  /* The following is not allowed because we try to perform INSERT AS
     SELECT data INTO LOB */
  INSERT INTO print_media(product_id, ad_id, ad_sourcetext)
    SELECT 2056, 5, bigtext FROM dual;

END;
/

LOB用のデータ・インタフェースを使用したINSERT、UPDATEおよびSELECT操作

LOBに対するINSERT文およびUPDATE文の使用方法は、LONGに対する使用方法と同じです。次に例を示します。

DECLARE
  ad_buffer VARCHAR2(100);
BEGIN
  INSERT INTO print_media(product_id, ad_id, ad_sourcetext)
    VALUES(2004, 5, 'Source for advertisement 1');
  UPDATE print_media SET ad_sourcetext= 'Source for advertisement 2'
    WHERE product_id=2004 AND ad_id=5;
  /* This retrieves the LOB column if it is up to 100 bytes, otherwise it
   * raises an exception */
  SELECT ad_sourcetext INTO ad_buffer FROM print_media 
    WHERE product_id=2004 AND ad_id=5;
END;
/

LOB用のデータ・インタフェースを使用した割当てとパラメータの受渡し

LOB用のデータ・インタフェースを使用すると、次の例に示すように暗黙的な割当てとパラメータの受渡しが可能です。

CREATE TABLE t (clob_col CLOB, blob_col BLOB);
INSERT INTO t VALUES('abcdefg', 'aaaaaa');

DECLARE
  var_buf VARCHAR2(100);
  clob_buf CLOB;
  raw_buf RAW(100);
  blob_buf BLOB;
BEGIN
  SELECT * INTO clob_buf, blob_buf FROM t;
  var_buf := clob_buf;
  clob_buf:= var_buf;
  raw_buf := blob_buf;
  blob_buf := raw_buf;
END;
/

CREATE OR REPLACE PROCEDURE FOO ( a IN OUT CLOB) IS
BEGIN
  -- Any procedure body
  a := 'abc';
END;
/

CREATE OR REPLACE PROCEDURE BAR (b IN OUT VARCHAR2) IS
BEGIN
  -- Any procedure body
  b := 'xyz';
END;
/

DECLARE
  a VARCHAR2(100) := '1234567';
  b CLOB;
BEGIN
  FOO(a);
  SELECT clob_col INTO b FROM t;
  BAR(b);
END;
/

LOB用のデータ・インタフェースを使用したPL/SQL組込みファンクション

この例では、LOB用のデータ・インタフェースを使用した、PL/SQL組込みファンクションでのCLOBの使用を示します。

DECLARE
  my_ad CLOB;
  revised_ad CLOB;
  myGist VARCHAR2(100):= 'This is my gist.';
  revisedGist VARCHAR2(100);
BEGIN
  INSERT INTO print_media (product_id, ad_id, ad_sourcetext)
    VALUES (2004, 5, 'Source for advertisement 1');  

  -- select a CLOB column into a CLOB variable
  SELECT ad_sourcetext INTO my_ad FROM print_media 
    WHERE product_id=2004 AND ad_id=5;

  -- perform VARCHAR2 operations on a CLOB variable
  revised_ad := UPPER(SUBSTR(my_ad, 1, 20));
 
  -- revised_ad is a temporary LOB
  -- Concat a VARCHAR2 at the end of a CLOB
  revised_ad := revised_ad || myGist;

  -- The following statement raises an error if my_ad is
  -- longer than 100 bytes
  myGist := my_ad;
END;
/

OCIにおける永続LOB用のデータ・インタフェースの使用

この項では、永続LOB用のデータ・インタフェースに組み込まれているOCI関数について説明します。この種のOCI関数は、LONGデータ型の場合と同様にLOBデータ型にも機能します。この種の関数を使用すると、文字データまたはバイナリ・データを格納する他のデータ型に使用するのと同じ方法で、OCIでLOBに対してINSERTUPDATE、フェッチ、バインドおよび定義操作を実行できます。


注意:

配列のバインドおよび定義インタフェースを使用すると、LOBを含む複数の行を1回のラウンドトリップで挿入および選択できます。


関連項目:

『Oracle Call Interfaceプログラマーズ・ガイド』OCIでのランタイム・データの割当てとピース単位操作に関する項

OCIでのLOBデータ型のバインド

次の操作でLOBデータ型をバインドできます。

  • INSERT操作およびUPDATE操作に対する標準、ピース単位およびコールバックのバインド

  • INSERT操作およびUPDATE操作に対する配列のバインド

  • PL/SQLとOCIの境界でのパラメータの受渡し

ピース単位操作は、ポーリングまたはコールバックによって実行できます。これらの操作をサポートするために、次のOCI関数は表20-2に示すLONGデータ型とLOBデータ型を受け入れます。

  • OCIBindByName()およびOCIBindByPos()

    これらの関数を使用して、INSERT操作およびUPDATE操作用にSQL文またはPL/SQLブロック内のプログラム変数とプレースホルダ間の対応付けを行います。

  • OCIBindDynamic()

    このコールを使用して、INSERT操作またはUPDATE操作用に動的にデータを割り当てるためのコールバックを登録します。

  • OCIStmtGetPieceInfo()およびOCIStmtSetPieceInfo()

    これらのコールを使用して、ピース単位操作のためのピース情報を取得または設定します。

OCIでのLOBデータ型の定義

永続LOB用のデータ・インタフェースを使用すると、次のOCI関数で表20-2に示すLONGデータ型とLOBデータ型を受け入れることができます。

  • OCIDefineByPos()

    このコールを使用して、SELECTリストにある項目を型および出力データ・バッファに対応付けます。

  • OCIDefineDynamic()

    このコールを使用して、OCIDefineByPos()関数のコールでOCI_DYNAMIC_FETCHモードが選択された場合、SELECT操作に対してユーザー・コールバックを登録します。

これらの関数をLOB型に使用すると、LOBロケータではなくLOBデータがバッファに選択されます。OCIでは、LOB用のデータ・インタフェースを使用して読み取る量を指定できないことに注意してください。指定できるのは、バッファ長のみです。バッファに収まる量のデータのみが読み取られ、データが切り捨てられます。

LOB用データ・インタフェースでのOCIのマルチバイト・キャラクタ・セットの併用

クライアントのキャラクタ・セットがマルチバイト形式の場合、データ・インタフェースに組み込まれている関数は、次のように、LONGデータ型の場合と同様にLOBデータ型を操作します。

  • マルチバイト・キャラクタ・セットでのピース単位フェッチの場合、マルチバイト文字が途中で切れることがあり、一部のバイトが1つのバッファの最後に、残りのバイトが次のバッファに入ることがあります。

  • 通常のフェッチの場合、最後の文字のバイトの一部をバッファで保持できない場合には、バッファに収まるかぎりのバイトが戻されるため、部分的な文字にしかなりません。

OCI関数を使用したLOB列のINSERTまたはUPDATEの実行

この項では、データ・インタフェースを使用してLOB列またはLOB属性のINSERT操作またはUPDATE操作を実行する各種の方法について説明します。この項で説明する操作は、OCI環境を初期化して必要なハンドルをすべて割当て済であることを前提としています。

1つのピースでの標準のINSERTまたはUPDATE

永続LOB用のデータ・インタフェースを使用して、1つのピースで単純なINSERT操作またはUPDATE操作を実行する手順は、次のとおりです。

  1. OCIStmtPrepare()OCI_DEFAULTモードでコールして、文を準備します。

  2. OCIBindByName()またはOCIBindbyPos()OCI_DEFAULTモードでコールして、LOBを文字データまたはバイナリ・データとしてバインドするためにプレースホルダをバインドします。

  3. OCIStmtExecute()をコールして、実際のINSERT操作またはUPDATE操作を実行します。

ポーリングによるピース単位のINSERTおよびUPDATE

永続LOB用のデータ・インタフェースを使用して、ポーリングによりピース単位のINSERT操作またはUPDATE操作を実行する手順は、次のとおりです。

  1. OCIStmtPrepare()OCI_DEFAULTモードでコールして、文を準備します。

  2. OCIBindByName()またはOCIBindbyPos()OCI_DATA_AT_EXECモードでコールして、LOBを文字データまたはバイナリ・データとしてバインドします。

  3. OCIStmtExecute()をデフォルト・モードでコールします。OCIStmtExecute()から戻される値がOCI_NEED_DATAの間は、ループ内で次の各手順を実行します。OCIStmtExecute()から値OCI_SUCCESSが戻された場合は、ループを終了します。

    • OCIStmtGetPieceInfo()をコールして、挿入するピースの情報を取り出します。

    • OCIStmtSetPieceInfo()をコールして、挿入するピースの情報を設定します。

コールバックによるピース単位のINSERTおよびUPDATE

永続LOB用のデータ・インタフェースを使用して、コールバックによりピース単位のINSERT操作またはUPDATE操作を実行する手順は、次のとおりです。

  1. OCIStmtPrepare()OCI_DEFAULTモードでコールして、文を準備します。

  2. OCIBindByName()またはOCIBindbyPos()OCI_DATA_AT_EXECモードでコールして、LOB列を文字データまたはバイナリ・データとしてバインドするためにプレースホルダをバインドします。

  3. OCIBindDynamic()をコールしてコールバックを指定します。

  4. OCIStmtExecute()をデフォルト・モードでコールします。

配列のINSERT操作およびUPDATE操作

永続LOB用のデータ・インタフェースを使用して配列のINSERT操作またはUPDATE操作を実行するには、この項で説明する方法のいずれかをOCIBindArrayOfStruct()とともに使用する方法と、OCIStmtExecute()のコールで反復回数(iter)のiter値を2以上に指定する方法があります。

データ・インタフェースを使用したOCIでのLOBデータのフェッチ

この項では、永続LOB用のデータ・インタフェースを使用して、OCIでLOB列またはLOB属性からデータをフェッチする方法について説明します。

1つのピースでの標準のフェッチ

永続LOB用のデータ・インタフェースを使用し、1つのピースでLOBに対して単純なフェッチ操作を実行する手順は、次のとおりです。

  1. OCIStmtPrepare()OCI_DEFAULTモードでコールして、SELECT文を準備します。

  2. OCIDefineByPos()OCI_DEFAULTモードでコールして、LOBを文字データまたはバイナリ・データとして定義するために、選択リストの位置を定義します。

  3. OCIStmtExecute()をコールしてSELECT文を実行します。

  4. OCIStmtFetch()をコールして実際のフェッチを実行します。

ポーリングによるピース単位のフェッチ

LOB用のデータ・インタフェースを使用し、LOB列に対してポーリングによるピース単位フェッチ操作を実行する手順は、次のとおりです。

  1. OCIStmtPrepare()OCI_DEFAULTモードでコールして、SELECT文を準備します。

  2. OCIDefineByPos()OCI_DYNAMIC_FETCHモードでコールして、LOB列を文字データまたはバイナリ・データとして定義するために、選択リストの位置を定義します。

  3. OCIStmtExecute()をコールしてSELECT文を実行します。

  4. OCIStmtFetch()をデフォルト・モードでコールします。OCIStmtFetch()から戻される値がOCI_NEED_DATAである間、ループで次の各手順を実行します。OCIStmtFetch()で戻される値がOCI_SUCCESSになると、ループは停止します。

    • OCIStmtGetPieceInfo()をコールして、フェッチするピースの情報を取り出します。

    • OCIStmtSetPieceInfo()をコールして、フェッチするピースの情報を設定します。

コールバックによるピース単位のフェッチ

永続LOB用のデータ・インタフェースを使用し、LOB列に対してコールバックによるピース単位フェッチ操作を実行する手順は、次のとおりです。

  1. OCIStmtPrepare()OCI_DEFAULTモードでコールして、文を準備します。

  2. OCIDefineByPos()OCI_DYNAMIC_FETCHモードでコールして、LOB列を文字データまたはバイナリ・データとして定義するために、選択リストの位置を定義します。

  3. OCIStmtExecute()をコールしてSELECT文を実行します。

  4. OCIDefineDynamic()をコールしてコールバックを指定します。

  5. OCIStmtFetch()をデフォルト・モードでコールします。

配列のフェッチ

永続LOB用のデータ・インタフェースを使用してOCIで配列フェッチを実行するには、この項で説明する方法のいずれかをOCIDefineArrayOfStruct()とともに使用する方法と、OCIStmtExecute()のコールで反復回数(iter)のiter値を2以上に指定する方法があります。

OCIからのPL/SQLバインドおよびCバインド

OCIからPL/SQLプロシージャをコールして、インバインドまたはアウトバインド(あるいはその両方)を行う場合、次のいずれかを行えます。

  • PL/SQLプロシージャの仮パラメータがSQLT_CLOBである場合、変数をSQLT_CHRまたはSQLT_LNGとしてバインドする。

  • 仮パラメータがSQLT_BLOBである場合、変数をSQLT_BINまたはSQLT_LBIとしてバインドする。

次に、有効な2つの例を示します。

begin foo(:1); end;形式でのPL/SQLアウトバインドのコール

begin foo(:1); end;形式でPL/SQLアウトバインドをコールする例を次に示します。

text *sqlstmt = (text *)"BEGIN get_lob(:c); END; " ;

call foo(:1);形式でのPL/SQLアウトバインドのコール

call foo(:1);形式でPL/SQLアウトバインドをコールする例を次に示します。

text *sqlstmt = (text *)"CALL get_lob(:c);" ;

どちらの例でも、プログラムの後半には次の文が含まれます。

OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt),
               (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
   curlen = 0;
OCIBindByName(stmthp, &bndhp[3], errhp,
        (text *) ":c", (sb4) strlen((char *) ":c"),
        (dvoid *) buf5, (sb4) LONGLEN, SQLT_CHR,
        (dvoid *) 0, (ub2 *) 0, (ub2 *) 0,
        (ub4) 1, (ub4 *) &curlen, (ub4) OCI_DATA_AT_EXEC);

PL/SQLプロシージャget_lob()を次に示します。

procedure get_lob(c INOUT CLOB) is  -- This might have been column%type 
  BEGIN
  ... /* The procedure body could be in PL/SQL or C*/
  END;

例: C(OCI): INSERTおよびUPDATEでの4000バイトを超えるバインド

void insert3() 
{ 
/* Insert of data into LOB attributes is allowed. */
   ub1 buffer[8000]; 
   text *insert_sql = (text *)"INSERT INTO Print_media (ad_header) \
               VALUES (adheader_typ(NULL, NULL, NULL,:1))"; 
   OCIStmtPrepare(stmthp, errhp, insert_sql, strlen((char*)insert_sql),  
            (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT); 
   OCIBindByPos(stmthp, &bindhp[0], errhp, 1, (dvoid *)buffer, 2000,  
             SQLT_LNG, 0, 0, 0, 0, 0, (ub4) OCI_DEFAULT); 
   OCIStmtExecute(svchp, stmthp, errhp, 1, 0, (const OCISnapshot*) 0, 
                  (OCISnapshot*)0, OCI_DEFAULT); 
}

LOB用データ・インタフェースを使用したLOBに対するOCIからのPL/SQLバインド

LOB用のデータ・インタフェースを使用すると、OCIからのLOBのPL/SQLバインドを次のように使用できます。OCIからPL/SQLプロシージャをコールして、INOUTまたはIN OUTバインドを実行すると、PL/SQLプロシージャの仮パラメータがSQLT_CLOBである場合、変数をSQLT_CHRとしてバインドできます。


注意:

CプロシージャはPL/SQLスタブにラップされています。そのため、OCIアプリケーションは常にPL/SQLスタブをコールします。

OCIをコールするプログラムでは、次のような場合が考えられます。

begin foo(:1); end;形式でのPL/SQLアウトバインドのコール

次に例を示します。

text *sqlstmt = (text *)"BEGIN PKG1.P5 (:c); END; " ;

call foo(:1);形式でのPL/SQLアウトバインドのコール

次に例を示します。

text *sqlstmt = (text *)"CALL PKG1.P5( :c );" ;

どちらの例でも、プログラムの後半は次のようになります。

   OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt),
            (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
   curlen = 0;

   OCIBindByName(stmthp, &bndhp[3], errhp,
            (text *) ":c4", (sb4) strlen((char *) ":c"),
            (dvoid *) buf5, (sb4) LONGLEN, SQLT_CHR,
            (dvoid *) 0, (ub2 *) 0, (ub2 *) 0,
            (ub4) 1, (ub4 *) &curlen, (ub4) OCI_DATA_AT_EXEC);

    OCIStmtExecute(svchp, stmthp, errhp,(ub4) 0,(ub4) 0, (const OCISnapshot*) 0,
            (OCISnapshot*) 0,(ub4) OCI_DEFAULT);

PL/SQLプロシージャPKG1.P5を次に示します。

   CREATE OR REPLACE PACKAGE BODY pkg1 AS
     ...
   procedure p5 (c OUT CLOB) is
     -- This might have been table%rowtype (so it   is CLOB now)
   BEGIN
     ...
   END p5;

END pkg1;

4000バイトを超えるバインドでのLOB列に対するLONGデータのバインド

次の例に、LOB列の文字データのバインドを示します。

void simple_insert()
{
  word buflen;
  text buf[5000];
  text *insstmt = (text *) "INSERT INTO Print_media(Product_id, Ad_id,\
                  Ad_sourcetext) VALUES (2004, 1, :SRCTXT)";
 
  OCIStmtPrepare(stmthp, errhp, insstmt, (ub4)strlen((char *)insstmt), 
                (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
  
  OCIBindByName(stmthp, &bndhp[0], errhp,
                (text *) ":SRCTXT", (sb4) strlen((char *) ":SRCTXT"),
                (dvoid *) buf, (sb4) sizeof(buf), SQLT_CHR,
                (dvoid *) 0, (ub2 *) 0, (ub2 *) 0,
                (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT);
 
  memset((void *)buf, (int)'A', (size_t)5000);
  OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
                 (const OCISnapshot*) 0, (OCISnapshot*) 0, (ub4) OCI_DEFAULT);
}

ポーリングによるピース単位INSERTを使用したLOB列へのLONGデータのバインド

次の例に、LOB用のデータ・インタフェースとともにポーリングによるピース単位INSERTを使用する例を示します。

void piecewise_insert()
{
  text *sqlstmt = (text *)"INSERT INTO Print_media(Product_id, Ad_id,\
                  Ad_sourcetext) VALUES (:1, :2, :3)";
  ub2 rcode;
  ub1 piece, i;
  word product_id = 2004;
  word ad_id = 2;
  ub4 buflen;
  char buf[5000];
 
  OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt), 
                 (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
  OCIBindByPos(stmthp, &bndhp[0], errhp, (ub4) 1,
               (dvoid *) &product_id, (sb4) sizeof(product_id), SQLT_INT,
               (dvoid *) 0, (ub2 *)0, (ub2 *)0,
               (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT);
  OCIBindByPos(stmthp, &bndhp[1], errhp, (ub4) 2,
               (dvoid *) &ad_id, (sb4) sizeof(ad_id), SQLT_INT,
               (dvoid *) 0, (ub2 *)0, (ub2 *)0,
               (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT);
  OCIBindByPos(stmthp, &bndhp[2], errhp, (ub4) 3,
               (dvoid *) 0, (sb4) 15000, SQLT_LNG,
               (dvoid *) 0, (ub2 *)0, (ub2 *)0,
               (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC);
 
  i = 0;
  while (1)
  {
    i++;
    retval = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
                            (CONST OCISnapshot*) 0, (OCISnapshot*) 0,
                            (ub4) OCI_DEFAULT);
    switch(retval)
    {
    case OCI_NEED_DATA:
      memset((void *)buf, (int)'A'+i, (size_t)5000);
      buflen = 5000;
      if (i == 1) piece = OCI_FIRST_PIECE;
      else if (i == 3) piece = OCI_LAST_PIECE;
      else piece = OCI_NEXT_PIECE;
 
      if (OCIStmtSetPieceInfo((dvoid *)bndhp[2],
                              (ub4)OCI_HTYPE_BIND, errhp, (dvoid *)buf,
                              &buflen, piece, (dvoid *) 0, &rcode))
        {
          printf("ERROR: OCIStmtSetPieceInfo: %d \n", retval);
          break;
        }
      
      break;
    case OCI_SUCCESS:
      break;
    default:
      printf( "oci exec returned %d \n", retval);
      report_error(errhp);
      retval = OCI_SUCCESS;
    } /* end switch */
    if (retval == OCI_SUCCESS) 
      break;
  } /* end while(1) */
}

コールバックによるピース単位INSERTを使用したLOB列へのLONGデータのバインド

次の例に、コールバックによるピース単位INSERTを使用する場合の、LOB列へのLONGデータのバインドを示します。

void callback_insert()
{
  word buflen = 15000;
  word product_id = 2004;
  word ad_id = 3;
  text *sqlstmt = (text *) "INSERT INTO Print_media(Product_id, Ad_id,\
                  Ad_sourcetext) VALUES (:1, :2, :3)";
  word pos = 3;
 
  OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt),
                 (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)
 
  OCIBindByPos(stmthp, &bndhp[0], errhp, (ub4) 1,
               (dvoid *) &product_id, (sb4) sizeof(product_id), SQLT_INT,
               (dvoid *) 0, (ub2 *)0, (ub2 *)0,
               (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT);
  OCIBindByPos(stmthp, &bndhp[1], errhp, (ub4) 2,
               (dvoid *) &ad_id, (sb4) sizeof(ad_id), SQLT_INT,
               (dvoid *) 0, (ub2 *)0, (ub2 *)0,
               (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT);
  OCIBindByPos(stmthp, &bndhp[2], errhp, (ub4) 3,
               (dvoid *) 0, (sb4) buflen, SQLT_CHR,
               (dvoid *) 0, (ub2 *)0, (ub2 *)0,
               (ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC);
 
  OCIBindDynamic(bndhp[2], errhp, (dvoid *) (dvoid *) &pos,
                 insert_cbk, (dvoid *) 0, (OCICallbackOutBind) 0);
 
  OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
                 (const OCISnapshot*) 0, (OCISnapshot*) 0,
                 (ub4) OCI_DEFAULT);
} /* end insert_data() */
 
/* Inbind callback to specify input data. */
static sb4 insert_cbk(dvoid *ctxp, OCIBind *bindp, ub4 iter, ub4 index,
                       dvoid **bufpp, ub4 *alenpp, ub1 *piecep, dvoid **indpp)
{
  static int a = 0;
  word   j;
  ub4    inpos = *((ub4 *)ctxp);
  char   buf[5000];
 
  switch(inpos)
  {
  case 3:
    memset((void *)buf, (int) 'A'+a, (size_t) 5000);
    *bufpp = (dvoid *) buf;
    *alenpp = 5000 ;
    a++;
    break;
  default: printf("ERROR: invalid position number: %d\n", inpos);
  }
 
  *indpp = (dvoid *) 0;
  *piecep = OCI_ONE_PIECE;
  if (inpos == 3)
  {
    if (a<=1)
    {
      *piecep = OCI_FIRST_PIECE;
      printf("Insert callback: 1st piece\n");
    }
    else if (a<3)
    {
      *piecep = OCI_NEXT_PIECE;
      printf("Insert callback: %d'th piece\n", a);
    }
    else {
      *piecep = OCI_LAST_PIECE;
      printf("Insert callback: %d'th piece\n", a);
      a = 0;
    }
  }
  return OCI_CONTINUE;
}

配列のINSERTを使用したLOB列へのLONGデータのバインド

次の例に、配列のINSERT操作を使用したLOB列への文字データのバインドを示します。

void array_insert()
{
  ub4 i;
  word buflen;
  word arrbuf1[5];
  word arrbuf2[5];
  text arrbuf3[5][5000];
  text *insstmt = (text *)"INSERT INTO Print_media(Product_id, Ad_id,\
                  Ad_sourcetext) VALUES (:PID, :AID, :SRCTXT)";
 
  OCIStmtPrepare(stmthp, errhp, insstmt,
                 (ub4)strlen((char *)insstmt), (ub4) OCI_NTV_SYNTAX,
                 (ub4) OCI_DEFAULT);
 
  OCIBindByName(stmthp, &bndhp[0], errhp,
                (text *) ":PID", (sb4) strlen((char *) ":PID"),
                (dvoid *) &arrbuf1[0], (sb4) sizeof(arrbuf1[0]), SQLT_INT,
                (dvoid *) 0, (ub2 *)0, (ub2 *) 0,
                (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT);
 
  OCIBindByName(stmthp, &bndhp[1], errhp,
                (text *) ":AID", (sb4) strlen((char *) ":AID"),
                (dvoid *) &arrbuf2[0], (sb4) sizeof(arrbuf2[0]), SQLT_INT,
                (dvoid *) 0, (ub2 *)0, (ub2 *) 0,
                (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT);
 
  OCIBindByName(stmthp, &bndhp[2], errhp,
                (text *) ":SRCTXT", (sb4) strlen((char *) ":SRCTXT"),
                (dvoid *) arrbuf3[0], (sb4) sizeof(arrbuf3[0]), SQLT_CHR,
                (dvoid *) 0, (ub2 *) 0, (ub2 *) 0,
                (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT);
 
  OCIBindArrayOfStruct(bndhp[0], errhp sizeof(arrbuf1[0]),
                       indsk, rlsk, rcsk);
  OCIBindArrayOfStruct(bndhp[1], errhp, sizeof(arrbuf2[0]),
                       indsk, rlsk, rcsk);
  OCIBindArrayOfStruct(bndhp[2], errhp, sizeof(arrbuf3[0]),
                       indsk, rlsk, rcsk);
 
  for (i=0; i<5; i++)
  {
    arrbuf1[i] = 2004;
    arrbuf2[i] = i+4;
    memset((void *)arrbuf3[i], (int)'A'+i, (size_t)5000);
  }
  OCIStmtExecute(svchp, stmthp, errhp, (ub4) 5, (ub4) 0,
                 (const OCISnapshot*) 0, (OCISnapshot*) 0,
                 (ub4) OCI_DEFAULT);
 
}

単純フェッチを使用したLONGバッファへのLOB列の選択

次の例に、単純フェッチを使用したLOB列の選択を示します。

void simple_fetch()
{
  word retval;
  text buf[15000];
  text *selstmt = (text *) "SELECT Ad_sourcetext FROM Print_media WHERE\
                  Product_id = 2004";
 
  OCIStmtPrepare(stmthp, errhp, selstmt, (ub4)strlen((char *)selstmt),
                 (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
 
  retval = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, (ub4) 0,
                          (const OCISnapshot*) 0, (OCISnapshot*) 0,
                          (ub4) OCI_DEFAULT);
  while (retval == OCI_SUCCESS || retval == OCI_SUCCESS_WITH_INFO)
  {
    OCIDefineByPos(stmthp, &defhp, errhp, (ub4) 1, (dvoid *) buf,
                   (sb4) sizeof(buf), (ub2) SQLT_CHR, (dvoid *) 0,
                   (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT);
    retval = OCIStmtFetch(stmthp, errhp, (ub4) 1,
                          (ub4) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT);
    if (retval == OCI_SUCCESS || retval == OCI_SUCCESS_WITH_INFO)
      printf("buf = %.*s\n", 15000, buf);
  }
}

ポーリングによるピース単位フェッチを使用したLONGバッファへのLOB列の選択

次の例に、ポーリングによるピース単位フェッチを使用した、LONGバッファへのLOB列の選択を示します。

void piecewise_fetch()
{
  text buf[15000];
  ub4 buflen=5000;
  word retval;
  text *selstmt = (text *) "SELECT Ad_sourcetext FROM Print_media
                  WHERE Product_id = 2004 AND Ad_id = 2";
 
  OCIStmtPrepare(stmthp, errhp, selstmt,
                 (ub4) strlen((char *)selstmt),
                 (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
 
  OCIDefineByPos(stmthp, &dfnhp, errhp, (ub4) 1,
                 (dvoid *) NULL, (sb4) 100000, SQLT_LNG,
                 (dvoid *) 0, (ub2 *) 0,
                 (ub2 *) 0, (ub4) OCI_DYNAMIC_FETCH);
 
  retval = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, (ub4) 0,
                          (CONST OCISnapshot*) 0, (OCISnapshot*) 0,
                          (ub4) OCI_DEFAULT);
 
  retval = OCIStmtFetch(stmthp, errhp, (ub4) 1 ,
                        (ub2) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT);
 
  while (retval != OCI_NO_DATA && retval != OCI_SUCCESS)
  {
    ub1 piece;
    ub4 iter;
    ub4 idx;
  
    genclr((void *)buf, 5000);
    switch(retval)
    {
    case OCI_NEED_DATA:
      OCIStmtGetPieceInfo(stmthp, errhp, &hdlptr, &hdltype,
                          &in_out, &iter, &idx, &piece);
      buflen = 5000;
      OCIStmtSetPieceInfo(hdlptr, hdltype, errhp,
                          (dvoid *) buf, &buflen, piece,
                          (CONST dvoid *) &indp1, (ub2 *) 0);
      retval = OCI_NEED_DATA;
      break;
    default:
      printf("ERROR: piece-wise fetching, %d\n", retval);
      return;
    } /* end switch */
    retval = OCIStmtFetch(stmthp, errhp, (ub4) 1 ,
                          (ub2) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT);
    printf("Data : %.5000s\n", buf);
  } /* end while */
}

コールバックによるピース単位フェッチを使用したLONGバッファへのLOB列の選択

次の例に、コールバックによるピース単位フェッチを使用した、LOBバッファへのLONG列の選択を示します。

char buf[5000];
void callback_fetch()
{
  word outpos = 1;
  text *sqlstmt = (text *) "SELECT Ad_sourcetext FROM Print_media WHERE
                  Product_id = 2004 AND Ad_id = 3";
  
  OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt),
                 (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
  OCIDefineByPos(stmthp, &dfnhp[0], errhp, (ub4) 1,
                 (dvoid *) 0, (sb4)3 * sizeof(buf), SQLT_CHR,
                 (dvoid *) 0, (ub2 *)0, (ub2 *)0,
                 (ub4) OCI_DYNAMIC_FETCH);
  
  OCIDefineDynamic(dfnhp[0], errhp, (dvoid *) &outpos,
                   (OCICallbackDefine) fetch_cbk);
 
  OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
                 (const OCISnapshot*) 0, (OCISnapshot*) 0,
                 (ub4) OCI_DEFAULT);
  buf[ 4999 ] = '\0';
  printf("Select callback: Last piece: %s\n", buf);
}
 
/* -------------------------------------------------------------- */
/* Fetch callback to specify buffers. */
/* -------------------------------------------------------------- */
static sb4 fetch_cbk(dvoid *ctxp, OCIDefine *dfnhp, ub4 iter, dvoid **bufpp, 
                      ub4 **alenpp, ub1 *piecep, dvoid **indpp, ub2 **rcpp)
{
  static int a = 0;
  ub4 outpos = *((ub4 *)ctxp);
  ub4 len = 5000;
  switch(outpos)
  {
  case 1:
    a ++;
    *bufpp = (dvoid *) buf;
    *alenpp = &len;
    break;
  default:
    *bufpp = (dvoid *) 0;
    *alenpp = (ub4 *) 0;
    printf("ERROR: invalid position number: %d\n", outpos);
  }
  *indpp = (dvoid *) 0;
  *rcpp = (ub2 *) 0;
 
  buf[len] = '\0';
  if (a<=1)
  {
    *piecep = OCI_FIRST_PIECE;
    printf("Select callback: 0th piece\n");
  }
  else if (a<3)
  {
    *piecep = OCI_NEXT_PIECE;
    printf("Select callback: %d'th piece: %s\n", a-1, buf);
  }
  else {
    *piecep = OCI_LAST_PIECE;
    printf("Select callback: %d'th piece: %s\n", a-1, buf);
    a = 0;
  }
  return OCI_CONTINUE;
}

配列フェッチを使用したLONGバッファへのLOB列の選択

次の例に、配列フェッチを使用した、LONGバッファへのLOB列の選択を示します。

void array_fetch()
{
  word i;
  text arrbuf[5][5000];
  text *selstmt = (text *) "SELECT Ad_sourcetext FROM Print_media WHERE
                  Product_id = 2004 AND Ad_id >=4";
 
  OCIStmtPrepare(stmthp, errhp, selstmt, (ub4)strlen((char *)selstmt),
                 (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
 
  OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, (ub4) 0,
                 (const OCISnapshot*) 0, (OCISnapshot*) 0, (ub4) OCI_DEFAULT);
 
  OCIDefineByPos(stmthp, &defhp1, errhp, (ub4) 1,
                   (dvoid *) arrbuf[0], (sb4) sizeof(arrbuf[0]),
                   (ub2) SQLT_CHR, (dvoid *) 0,
                   (ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT);
 
  OCIDefineArrayOfStruct(dfnhp1, errhp, sizeof(arrbuf[0]), indsk,
                         rlsk, rcsk);
 
  retval = OCIStmtFetch(stmthp, errhp, (ub4) 5,
                        (ub4) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT);
  if (retval == OCI_SUCCESS || retval == OCI_SUCCESS_WITH_INFO)
  {
     printf("%.5000s\n", arrbuf[0]);
     printf("%.5000s\n", arrbuf[1]);
     printf("%.5000s\n", arrbuf[2]);
     printf("%.5000s\n", arrbuf[3]);
     printf("%.5000s\n", arrbuf[4]);
  }
}

Javaにおける永続LOB用のデータ・インタフェースの使用

CLOBデータおよびBLOBデータの読取りおよび書込みは、LONGデータおよびLONG RAWデータの場合と同じストリーミング・メカニズムを使用して行うこともできます。読み取る場合は、列でdefineColumnType(nn, Types.LONGVARCHAR)またはdefineColumnType(nn, Types.LONGVARBINARY)を使用します。これにより、LONGまたはLONG RAW列の場合と同様に、データに直接ストリームが生成されます。PreparedStatementへの入力には、BLOBまたはCLOBパラメータに対してsetBinaryStream()setCharacterStream()またはsetAsciiStream()を使用できます。これらの方法では、ストリーム・インタフェースを使用して、ストリーム内のデータからデータベース内にLOBを作成します。これら両方の技法によってデータベースのラウンドトリップが削減され、場合によってはパフォーマンスが向上します。適用される大幅な制限については、http://www.oracle.com/technology/でストリーム・データに関するJavadocを参照してください。

『Oracle JDBC開発者ガイドおよびリファレンス』で、次の内容を参照してください。


関連項目:

  • 『Oracle Database JDBC開発者ガイドおよびリファレンス』の「LOBとBFILEの操作」、LOB用のデータ・インタフェースに関する項

  • 『Oracle Database JDBC開発者ガイドおよびリファレンス』の「JDBC標準サポート」


リモートLOB用データ・インタフェースの使用

リモートLOBの挿入、更新および選択を行うためのデータ・インタフェース(dblinkを介したアクセス)は、Oracle Database 10gリリース2以上でサポートされています。次の項に示す例は、2つのスキーマ、dbs1およびdbs2で作成されたprint_media表についてのものです。例で使用されている表のCLOB列は、ad_finaltextです。次の項に示すPL/SQL、OCIおよびJavaについての例では、この1つの列に対してバインドおよび定義を使用していますが、複数の列にアクセスすることも可能です。次に、サポートされている機能とその制限を示します。

  • CLOBCHARまたはNCHARとして、NCLOBをCHARまたはNCHARとして定義できます。CLOBおよびNCLOBは、LONGとして定義できます。BLOBは、RAWまたはLONG RAWとして定義できます。

  • 配列のバインドおよび定義はサポートされています。

サポートされない構文

  • 複数のデータベースを使用する問合せはサポートされていません。

    SELECT t1.lobcol, a2.lobcol FROM t1, t2.lobcol@dbs2 a2 WHERE 
    LENGTH(t1.lobcol) = LENGTH(a2.lobcol);
    

    次の問合せもサポートされていません(PL/SQLブロック内)。

    SELECT t1.lobcol INTO varchar_buf1 FROM t1@dbs1
    UNION ALL
    SELECT t2.lobcol INTO varchar_buf2 FROM t2@dbs2;
    
  • リモートの永続LOB列に移動するデータに対するバインドおよび定義のみがサポートされているため、リモートLOBに対してCHARデータがバインドまたは定義されているPL/SQLで渡されるパラメータは、サポートされていないリモートの一時LOBが発生する可能性があるので許可されません。次の文ではすべて、エラーが生成されます。

    SELECT foo() INTO varchar_buf FROM table1@dbs2; -- foo returns a LOB
    
    SELECT foo()@dbs INTO char_val FROM DUAL; -- foo returns a LOB
    
    SELECT XMLType().getclobval INTO varchar_buf FROM table1@dbs2;
    
  • リモート・オブジェクトが次のようなビューである場合。

    CREATE VIEW v AS SELECT foo() a FROM ... ; -- foo returns a LOB
    /* The local database then tries to get the CLOB data and returns an error */
    SELECT a INTO varchar_buf FROM v@dbs2;
    

    これによってサポートされていないリモートの一時LOBが発生するため、エラーが戻されます。

  • RETURNING INTOでは、CHARCLOBの間の暗黙的な変換はサポートされていません。

  • 実引数がLOB型であり、リモート引数がVARCHAR2NVARCHAR2CHARNCHARまたはRAWである場合、PL/SQLパラメータの受渡しは許可されません。

PL/SQLにおけるリモート・データ・インタフェースの例

PL/SQLにおけるデータ・インタフェースでは、サイズが32KB未満のデータのみがサポートされています。次にPL/SQLの例を示します。

CONNECT pm
declare
  my_ad varchar(6000) := lpad('b', 6000, 'b');
BEGIN
  INSERT INTO print_media@dbs2(product_id, ad_id, ad_finaltext) 
       VALUES (10000, 10, my_ad);
  -- Reset the buffer value
  my_ad := 'a';
  SELECT ad_finaltext INTO my_ad FROM print_media@dbs2 
       WHERE product_id = 10000;
END;
/

ad_finaltextCLOBではなくBLOB列である場合、my_adRAW型である必要があります。LOBのサイズが32KB - 1を超えている場合、PL/SQLでは切捨てエラーが発生し、バッファの内容は未定義になります。

OCIにおけるリモート・データ・インタフェースの例

OCIにおけるデータ・インタフェースでは、サイズが2GB未満(sb4として宣言された変数の可能な最大値)のデータのみがサポートされています。次の疑似コードは、OCIプログラムの一部として拡張できます。

...
text *sql = (text *)"insert into print_media@dbs2
                    (product_id, ad_id, ad_finaltext) 
                    values (:1, :2, :3)";
OCIStmtPrepare(...);
OCIBindByPos(...); /* Bind data for positions 1 and 2
                     * which are independent of LOB */
OCIBindByPos(stmthp, &bndhp[2], errhp, (ub4) 3, 
             (dvoid *) charbuf1, (sb4) len_charbuf1, SQLT_CHR, 
             (dvoid *) 0, (ub2 *)0, (ub2 *)0, 0, 0, OCI_DEFAULT);
OCIStmtExecute(...);

...

text *sql = (text *)"select ad_finaltext from print_media@dbs2
                    where product_id = 10000";
OCIStmtPrepare(...);
OCIDefineByPos(stmthp, &dfnhp[2], errhp, (ub4) 1, 
             (dvoid *) charbuf2, (sb4) len_charbuf2, SQLT_CHR, 
             (dvoid *) 0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT);
OCIStmtExecute(...);
...

ad_finaltextCLOBではなくBLOBである場合、SQLT_BIN型を使用してバインドおよび定義します。LOBのサイズが2GB - 1を超えている場合、OCIでは切捨てエラーが発生し、バッファの内容は未定義になります。

JDBCにおけるリモート・データ・インタフェースの例

次のコード例は、3つのJDBCドライバ(データベース内のOCI、Thinおよびkprb)のすべてで機能します。

バインド:

非ストリーミング・モードの場合:

...
String sql = "insert into print_media@dbs2 (product_id, ad_id, ad_final_text)" +
             " values (:1, :2, :3)";
    PreparedStatement pstmt = conn.prepareStatement(sql);
    pstmt.setInt( 1, 2 );
    pstmt.setInt( 2, 20);
    pstmt.setString( 3, "Java string" );
    int rows = pstmt.executeUpdate();
...

ストリーミング・モードの場合、前述と同じコードが機能しますが、setString()文は次のいずれかで置き換えられます。

pstmt.setCharacterStream( 3, new LabeledReader(), 1000000 );
pstmt.setAsciiStream( 3, new LabeledAsciiInputStream(), 1000000 );

ここで、LabeledReader()およびLabeledAsciiInputStream()により、それぞれ文字ストリームおよびASCIIストリームが生成されます。ad_finaltextCLOBではなくBLOB列である場合、前述の例は、バインドがRAW型である場合に機能します。

pstmt.setBytes( 3, <some byte[] array> );

pstmt.setBinaryStream( 3, new LabeledInputStream(), 1000000 );

ここで、LabeledInputStream()によってバイナリ・ストリームが生成されます。

定義:

非ストリーミング・モードの場合:

OracleStatement stmt = (OracleStatement)(conn.createStatement());
  stmt.defineColumnType( 1, Types.VARCHAR );
  ResultSet rst = stmt.executeQuery("select ad_finaltext from print_media@dbs2" );
  while( rst.next() )
     {
       String s = rst.getString( 1 );
       System.out.println( s );
     }

ストリーミング・モードの場合:

OracleStatement stmt = (OracleStatement)(conn.createStatement());
  stmt.defineColumnType( 1, Types.LONGVARCHAR );
  ResultSet rst = stmt.executeQuery("select ad_finaltext from print_media@dbs2" );
  while( rst.next() )
     {
       Reader reader = rst.getCharacterStream( 1 );
       while( reader.ready() )
       {
         System.out.print( (char)(reader.next()) );
       }
       System.out.println();
     }

ad_finaltextCLOBではなくBLOB列である場合、前述の例は、定義がLONGVARBINARY型である場合に機能します。

...
   OracleStatement stmt = (OracleStatement)conn.createStatement();
 
   stmt.defineColumnType( 1, Types.INTEGER );
   stmt.defineColumnType( 2, Types.LONGVARBINARY );
 
   ResultSet rset = stmt.executeQuery("SELECT ID, LOBCOL FROM LOBTAB@MYSELF");
 
   while(rset.next())
    {
     /* using getBytes() */
     /*
     byte[] b = rset.getBytes("LOBCOL");
     System.out.println("ID: " + rset.getInt("ID") + "  length: " + b.length);
     */
 
        /* using getBinaryStream() */
        InputStream byte_stream = rset.getBinaryStream("LOBCOL");
        byte [] b = new byte [100000];
        int b_len = byte_stream.read(b);
        System.out.println("ID: " + rset.getInt("ID") + "  length: " + b_len);
 
        byte_stream.close();
    }
...

関連項目:

『Oracle Database JDBC開発者ガイドおよびリファレンス』の「LOBとBFILEの操作」、CLOBデータを挿入および取得するためのショートカットに関する項