ヘッダーをスキップ
Oracle Call Interfaceプログラマーズ・ガイド
11g リリース1(11.1)
E05677-02
  目次
目次
索引
索引

戻る
戻る
 
次へ
次へ
 

7 LOBおよびBFILEの操作

この章は、次の項目で構成されています。

LOBでのOCI関数の使用

OCIには、データベース内のラージ・オブジェクト(Large Object: LOB)で操作を実行するための一連の関数があります。永続LOB(BLOBCLOBNCLOB)はデータベースの表領域に格納されており、領域の最適化とアクセスの効率化を実現します。これらのLOBは、データベース・サーバーのトランザクションを完全にサポートしています。BFILEとは、データベース表領域外のサーバーのオペレーティング・システム・ファイルに格納された大型のデータ・オブジェクトのことです。

また、OCIは一時LOBもサポートしています。一時LOBは、LOBデータ上で操作するローカル変数のように使用することができます。

BFILEは読取り専用です。バイナリのBFILEのみをサポートしています。


関連項目

  • LOBの使用方法を示したコード例は、付録B「OCIデモ・プログラム」を参照してください。

  • 特定のLOBコードのサンプルは、$ORACLE_HOME/rdbms/demo/lobs/oci/を参照してください。

  • DBMS_LOBパッケージは、『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。

  • 『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』。


永続LOBの作成と変更

LOBインスタンスは永続的(データベースに格納)または一時的(アプリケーションの有効範囲内のみに存在)のいずれかである可能性があります。永続LOBと永続オブジェクトの概念を混同しないでください。

永続LOBの作成および変更には、次の2つの方法があります。

  1. データ・インタフェースの使用

    文字データをCLOB列に挿入、またはRAWデータをBLOB列に直接挿入すると、LOBを作成できます。SQLのUPDATE文を使用するか、文字データをCLOB列にバインドするか、またはRAWデータをBLOB列にバインドすると、LOBを変更することもできます。

    リモート・サーバーとローカル・サーバーがいずれもOracle Database 10g リリース2以上であれば、リモートLOBの(dblinkを介した)挿入、更新および選択がサポートされます。データ・インタフェースでは、最大2GB -1、つまりsb4の最大サイズまでのデータ・サイズのみサポートされます。


    関連項目:


    詳細と例は、『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』の「通常のLOB用のデータ・インタフェース」を参照してください。

  2. LOBロケータの使用

    内部LOBを新規作成するには、OCIDescriptorAlloc()を使用して新規のLOBロケータを初期化してから、OCIAttrSet()をコールして(OCI_ATTR_LOBEMPTY属性を使用して)空に設定し、次に、そのロケータをINSERT文でプレースホルダにバインドします。この処理により、LOB列または属性がある表に空のロケータを挿入します。次に、SELECT...FOR UPDATEでこの行を選択してロケータを取得し、OCI LOB関数の1つを使用してロケータに書き込みます。


    注意:


    LOB列または属性を変更(書込み、コピー、切捨てなど)するには、そのLOBが含まれている行をロックする必要があります。そのためには、操作を実行する前にSELECT...FOR UPDATE文を使用してロケータを選択します。


関連項目:


INSERTおよびUPDATEの使用方法および使用例は、「LOBデータのバインド」を参照してください。

LOB書込みコマンドを正常終了するには、トランザクションをオープンしておく必要があります。データの書込み前にトランザクションをコミットする場合は、(SELECT...FOR UPDATE文の再発行などにより)行を再ロックする必要があります。これは、コミットによってトランザクションがクローズされるためです。

表内のBFILEとオペレーティング・システム・ファイルの関連付け

INSERT文でBFILENAME()関数を使用すると、外部サーバー側(オペレーティング・システム)ファイルと表内のBFILE列または属性を関連付けることができます。UPDATE文でBFILENAME()を使用して、BFILEの列または属性を別のオペレーティング・システム・ファイルに関連付けます。OCILobFileSetName()を使用して、表内のBFILEをオペレーティング・システム・ファイルに関連付けることもできます。通常、BFILENAME()INSERTまたはUPDATE内でバインド変数なしで使用され、OCILobFileSetName()がバインド変数に使用されます。


関連項目:

  • 「OCILobFileSetName()」

  • BFILENAME()関数の詳細は、『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』を参照してください。


オブジェクトのLOB属性

OCIアプリケーションでは、OCIObjectNew()を使用してLOB属性を持つ永続オブジェクトまたは一時オブジェクトを作成することができます。

オブジェクトのLOB属性への書込み

OCIを使用して、LOB属性を持つ新規の永続オブジェクトを作成したり、そのLOB属性への書込みができます。LOBロケータを使用するときは、アプリケーションでは次のステップに従います。

  1. OCIObjectNew()をコールして、LOB属性を持つ永続オブジェクトを作成します。

  2. オブジェクトを「使用済」とマークします。

  3. 表に行を挿入して、オブジェクトをフラッシュします。

  4. オブジェクトをデータベースから取り出し、LOBに有効なロケータを取得して、オブジェクトの最新バージョンを再確保します(またはオブジェクトをリフレッシュします)。

  5. オブジェクトのLOBロケータを使用してOCILobWrite()をコールし、データを書き込みます。


    関連項目:


    オブジェクトの詳細は、第11章「OCIオブジェクト・リレーショナル・プログラミング」およびそれ以降の章を参照してください。

LOB属性への書込み方法はもう1つあります。データ・インタフェースを使用すると、CLOB属性に対して文字データ、BLOB属性に対してRAWデータをバインドまたは定義できます。


関連項目:


LOB属性を持つ一時オブジェクト

アプリケーションでは、OCIObjectNew()をコールして、内部LOB(BLOBCLOBNCLOB)属性を持つ一時オブジェクトを作成できます。ただし、LOB属性を持つ一時オブジェクトは現在サポートされていないため、読取りや書込みなどの、LOB属性での操作は実行できません。一時内部LOB型を作成するためのOCIObjectNew()コールは失敗しませんが、アプリケーションでは、この一時LOBでLOB操作を使用することはできません。

ただし、アプリケーションでは、BFILE属性を持つ一時オブジェクトを作成し、BFILE属性を使用して、サーバーのファイル・システムに格納されているファイルからデータを読み取ることができます。アプリケーションでは、OCIObjectNew()をコールして、一時BFILEを作成できます。

LOBの配列インタフェース

LOBを持つOCIの配列インタフェースは、他のデータ型と同じように使用できます。配列インタフェースを使用するには、次の2つの方法があります。

  1. データ・インタフェースの使用

    文字データの配列をCLOB列に対して、またはRAWデータの配列をBLOB列に対してバインドまたは定義できます。サーバーへの1回のラウンドトリップで、LOBを持つ複数の列を挿入および選択するインタフェースを、配列バインドを使用して定義できます。


    関連項目:


  2. LOBロケータの使用

    LOBロケータを使用するときは、次のように記述子を割り当てる必要があります。

    /* First create an array of OCILobLocator pointers: */
    OCILobLocator *lobp[10];
    
    for (i=0; i < 10; i++)
    { OCIDescriptorAlloc (...,&lobp[i],...);
    
    /* Then bind the descriptor as follows */
      OCIBindByPos(... &lobp[i], ...);
    }
    

4GBより大きいサイズのLOBの使用

OCIのOracle Database 10g リリース1からは、4GBより大きいサイズのLOBをサポートする新機能が導入されました。この新機能は、4GBより小さいLOBの新規アプリケーションでも使用できます。

Oracle Databaseでは、データベースのブロック・サイズとは異なるブロックサイズで表領域を作成できます。また、LOBの最大サイズは、表領域ブロックのサイズによって決まります。CHUNKはLOBストレージのパラメータで、その値はLOBが格納されている表領域のブロック・サイズによって制御されます。LOB列の作成時に、CHUNKに値を指定できます。この値が、LOB操作に割り当てられるバイト数です。値は、表領域のブロック・サイズの倍数に指定します。倍数でない場合は、次の倍数値に切り上げられます。(表領域のブロック・サイズがデータベースのブロック・サイズと同じ場合は、CHUNKもデータベースのブロック・サイズの倍数となります。)デフォルトのCHUNKサイズは表領域の1ブロックで、最大値は32Kです。

たとえば、データベースのブロック・サイズが32Kで、標準以外のブロック・サイズを持つ8Kの表領域を作成するとします。さらに、LOB列を持つテーブルを作成し、CHUNKサイズを16K(表領域のブロック・サイズである8Kの倍数)に指定するとします。この場合、この列のLOBの最大サイズは(4GB-1)×16Kです。

このマニュアルでは、4GBは4ギガバイト-1、または4,294,967,295バイトと定義します。LOB(永続または一時)の最大サイズは(4GB-1)×(CHUNK)です。LOBの最大サイズは、8〜128TBの範囲にできます。

BFILEの最大サイズは、ご使用のオペレーティング・システムで許容される最大ファイル・サイズとUB8MAXVALのどちらか小さい方となります。

以前のLOB関数ではub4を一部のパラメータのデータ型として使用するため、ub4データ型では最大4GBまでは保持のみできます。より新しい機能では、8バイト長のパラメータ、oraub8を使用します。これは、oratypes.hで定義されるデータ型です。コンパイラとオペレーティング・システムに応じて、データ型oraub8およびorasb8は該当する64ビット固有のデータ型にマップされます。厳密なANSIオプションを使用して32ビット・モードでコンパイルする場合、マクロを使用してoraub8およびorasb8を定義することはできません。

OCILobGetChunkSize()では、LOBの読取りおよび書込みに使用する値を、BLOBに対してはバイト数で、CLOBに対しては文字数で戻します。可変幅のキャラクタ・セットの場合は、値は同じ大きさのUnicode文字数です。チャンクに格納されるバイト数は、内部記憶域のオーバヘッドにより、実際にはCHUNKパラメータのサイズより小さくなります。関数OCILobGetStorageLimit()により、現行インストールにおける内部LOBの最大サイズがバイト単位で戻されます。


注意:


Oracle Databaseでは、どのようなプログラム環境においても、4GBを超えるBFILEはサポートされません。ご使用のオペレーティング・システムのその他のファイル・サイズ制限もBFILEに適用されます。

増加したLOBサイズに対する新機能

名前が「2」で終わり、データ型ub4のかわりにデータ型oraub8を使用する8つの関数がOracle Database 10g リリース1で導入されました。その他、いくつかの問題点を解決するために、読取りおよび書込みの関数(OCILobRead2()OCILobWrite2()およびOCILobWriteAppend2())で変更が行われています。

問題点: Oracle Database 10g リリース1より前では、パラメータamtpにより、LOBがバイト長または文字長のどちらであるかが、ロケータ・タイプおよびキャラクタ・セットに基づいて判断されていました。これは複雑で、ユーザーは要件に応じてバイト長または文字長を柔軟に使用することができませんでした。

解決策: 読取り/書込みコールでは、amtpパラメータのかわりにbyte_amtpおよびchar_amtpの両方を取ってください。char_amtpではCLOBNCLOBのプリファレンスを取ります。char_amtpが0(ゼロ)の場合、byte_amtpは入力としてのみ考慮されます。CLOBおよびNCLOBの出力時には、byte_amtpchar_amtpの両方が格納されます。BLOBおよびBFILEの場合、入力時も出力時もchar_amtpパラメータは無視されます。

問題点: OCILobRead2()では、ポーリング・モードを示すフラグがありません。ユーザーが「100バイトのバッファの空きがあります。可能なかぎり埋めてください。」ということを示す簡単な方法はありません。以前は、空きを埋める文字数を見積る必要がありました。見積りが多すぎた場合は、意図にかかわらず強制的にポーリング・モードになりました。このため、ユーザー・コードはポーリング・モードで取得される可能性があり、後続のOCIコールはすべてブロックされます。

解決策: このコールでは、pieceを入力パラメータとして取ります。OCI_ONE_PIECEが渡された場合は、byte_amtpまたはchar_amtpがバッファ長より大きい場合でも、このコールでバッファを可能なかぎり埋め、コールを明示する必要があります。buflの値を使用して、読み取るバイトの最大量を指定します。

問題点: ポーリング・モードでLOB書込みをコールした後は、ポーリングの終了までに実際にフェッチされる文字数またはバイト数をユーザーは認識できません。

解決策: ポーリング・モードでの各コール後に、byte_amtpおよびchar_amtpの両方を更新してください。

問題点: コールバックを使用した、ストリーム・モードでの読取り時または書込み時には、ユーザーはデータの各ピースに対して同じバッファを使用する必要があります。

解決策: コールバック関数には、新規バッファおよびバッファ長を指定する2つの新規パラメータを含めてください。コールバック関数では、新規バッファ・パラメータをNULLに設定して以前の動作(すべてのピースに対する最初のコールで渡されるデフォルト・バッファを使用)に準拠させる必要があります。

互換性および移行

既存のOCIプログラムを拡張して、(4GBより大きい)大容量のLOBデータを処理できます。表7-1に、互換性の問題点をまとめます(「旧」とは、Oracle Database 10g リリース1より前を指します)。

表7-1 LOB関数の互換性および移行

LOB関数 旧クライアント/新規または旧サーバー 新規クライアント/旧サーバー 新規クライアント/新規サーバー

OCILobArrayRead()

NA

ピース・サイズおよびオフセットが< 4GBまではOK

OK

OCILobArrayWrite()

NA

ピース・サイズおよびオフセットが< 4GBまではOK

OK

OCILobCopy2()

NA

LOBサイズ、ピース・サイズ(量)およびオフセットが< 4GBまではOK

OK

OCILobCopy()

OK(制限は4GB)

OK

OK(制限は4GB)

OCILobErase2()

NA

ピース・サイズおよびオフセットが< 4GBまではOK

OK

OCILobErase()

OK(制限は4GB)

OK

OK(制限は4GB)

OCILobGetLength2()

NA

OK

OK

OCILobGetLength()

OK(制限は4GB)

OK

OK(LOBサイズが > 4GBの場合はOCI_ERRORとなります)

OCILobLoadFromFile2()

NA

LOBサイズ、ピース・サイズ(量)およびオフセットが< 4GBまではOK

OK

OCILobLoadFromFile()

OK(制限は4GB)

OK

OK(制限は4GB)

OCILobRead2()

NA

LOBサイズ、ピース・サイズ(量)およびオフセットが< 4GBまではOK

OK

OCILobRead()

OK(制限は4GB)

新規サーバーを使用した場合: 任意の量>= 4GBを、任意のオフセット< 4GBから読み取ると、OCI_ERRORが戻されます。これは、ユーザーが任意の量>= 4GBを読み取ると、*amtpの戻り値がオーバーフローするためです。エラーとして表記されます。

注意:

1) オフセットから最大で4GB-1を読み取る場合は、エラーとして表記されません。

2) ポーリング・モードとともにストリーム・モードを使用すると、> 4GBのピース・サイズを使用しない場合(この場合、> 4GBのデータ読取りが可能)はエラーが戻されません。

OK

OK

任意の量>= 4GBを、任意のオフセット< 4GBから読み取ると、OCI_ERRORが戻されます。これは、ユーザーが任意の量>= 4GBを読み取ると、*amtpの戻り値がオーバーフローするためです。エラーとして表記されます。

注意:

1) オフセットから最大で4GB-1を読み取る場合は、エラーとして表記されません。

2) ポーリング・モードとともにストリーム・モードを使用すると、> 4GBのピース・サイズを使用しない場合はエラーが戻されません。

OCIlobTrim2()

NA

OK

OK

OCIlobTrim()

OK(制限は4GB)

OK

OK(制限は4GB)

OCILobWrite2()

NA

LOBサイズ、ピース・サイズ(量)およびオフセットが< 4GBまではOK

OK

OCILobWrite()

OK(制限は4GB)

新規サーバーを使用した場合:

任意の量 >= 4GBを(任意のオフセット< 4GBから)書き込むと、*amtpの戻り値がオーバーフローするため、OCI_ERRORが戻されます。

注意: 最大4GB-1のデータ量を使用して、最大4GB-1の任意のオフセットから10GBのLOBを更新すると、エラーとして表示されません。

OK

OK

任意の量>= 4GBを(任意のオフセット< 4GBから)書き込むと、*amtpの戻り値がオーバーフローするため、OCI_ERRORが戻されます。

注意: 最大4GB-1のデータ量を使用して、最大4GB-1の任意のオフセットから10GBのLOBを更新すると、エラーとして表示されません。

OCILobWriteAppend2()

NA

OK(LOBサイズおよびピース・サイズが< 4GBまで)

OK

OCILobWriteAppend()

OK(制限は4GB)

新規サーバーを使用した場合: 任意の量>= 4GBのデータを追加すると、*amtpの戻り値がオーバーフローするため、OCI_ERRORが戻されます。

OK

OK(制限は4GB)

任意の量>= 4GBのデータを追加すると、*amtpの戻り値がオーバーフローするため、OCI_ERRORが戻されます。

OCILobGetStorageLimit()

NA

エラー

OK


新規サーバーおよび新規クライアントを使用するときは、新機能を使用してください。旧機能と新機能を併用すると、予期せぬ状況となる可能性があります。たとえば、OCILobWrite2()を使用して書き込まれたデータが4GBより大きいときに、アプリケーションでOCILobRead()を使用してそれを読み取ると、データの一部のみが取得されます(コールバック関数が使用されていない場合)。サイズが4GBを超えていて、旧機能が使用されると、ほとんどの場合、アプリケーションでエラー・メッセージを受け取ります。ただし、サイズが4GBより小さいLOBに対して旧機能を使用する場合は、問題は発生しません。

OCIのLOB関数およびBFILE関数

データへのオフセットを伴うすべてのLOB操作では、オフセットは1から開始されます。OCILobCopy()OCILobErase()OCILobLoadFromFile()OCILobTrim()などのLOB操作の場合、amountパラメータは、クライアント側のキャラクタ・セットにかかわらず、CLOBNCLOBの文字数です。

これらのLOB操作は、サーバー上のLOBデータの量を参照します。クライアント側のキャラクタ・セットが可変幅の場合は、次の一般的な規則がLOBコールのamountパラメータとoffsetパラメータに適用されます。

これらの一般的な規則の例外は、特定のLOBコールの説明で示してあります。

LOBの読取り/書込みパフォーマンスの向上

次に、パフォーマンスを向上させるためのヒントをいくつか示します。

LOBに対するデータ・インタフェースの使用

CLOB列の文字データまたはBLOB列のRAWデータをバインドまたは定義できます。ここでは、複数回のラウンドトリップを必要とする従来のLOBインタフェースとは対照的に、LOBを挿入または選択する際に必要とするラウンドトリップは1回のみです。


関連項目:


OCILobGetChunkSize()の使用方法

OCILobGetChunkSize()は、利用可能なチャンク・サイズをBLOBに対してはバイト数で、CLOBおよびNCLOBに対しては文字数で戻します。 OCILobGetChunkSize()コールを使用して、BasicFile LOBに関するLOBの読取りおよび書込み操作のパフォーマンスを向上させることができます。サイズが利用可能なチャンク・サイズの倍数で、チャンクの境界から開始するBasicFile LOBデータを使用して読取りまたは書込みが行われると、パフォーマンスが向上します。OCILobGetChunkSize()の位置合せを使用してSecureFile LOBを読取りまたは書込みする必要はありません。

OCILobGetChunkSize()のコールにより、LOBの利用可能なチャンク・サイズが戻されるため、アプリケーションは、同じチャンクに対する複数のLOB書込みコールを発行するかわりに、チャンク全体に対する一連の書込み操作をバッチ処理できます。


注意:


OCILobGetChunkSize()は、可変幅の文字を格納するLOBに対してLOBチャンクに相当するUnicode文字の数を戻します。

OCILobWriteAppend2()の使用方法

OCIでは、LOBの末尾へのデータの書込みをより効率的にするためのショートカットが提供されています。OCILobWriteAppend2()により、最初にOCILobGetLength()をコールしてOCILobWrite()操作の開始点を決定しなくても、データをLOBの末尾に追加できます。OCILobWriteAppend2()では、両方のステップが行われます。

OCILobArrayRead()およびOCILobArrayWrite()の使用方法

Oracle Database 10g リリース2の関数を使用して、パフォーマンスを改善できます。詳細は、LOB関連ドキュメントのOCILobArrayRead()を使用して複数のロケータに対してLOBデータを読み取る方法、およびOCILobArrayWrite()を使用して複数のLOBロケータに対してLOBデータを書き込む方法を説明している項を参照してください。これらの関数をコールバック関数とともにピース単位モードで使用する場合のコード例も示されています。


関連項目:


『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』のLOB配列読取りに関する項およびLOB配列書込みに関する項

LOBバッファリング関数

Oracle OCIでは、内部LOB値の小さな読取りと書込みのために、次のように、LOBのバッファリングを制御するコールを提供します。

これらの関数により、アプリケーションで内部LOB(BLOBCLOBNCLOB)を使用して、クライアント側のバッファで小さな読取りと書込みをバッファできるため、パフォーマンスが向上します。これにより、ネットワーク・ラウンドトリップの回数とLOBのバージョンを削減でき、LOBのパフォーマンスが向上します。


関連項目:

  • 『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』。LOBバッファリングの詳細は、LOBに関する章を参照してください。

  • 各関数に必要なサーバー・ラウンドトリップ回数のリストは、「LOB関数のラウンドトリップ」を参照してください。


LOBのオープンおよびクローズのための関数

OCIでは、LOBを明示的にオープンするための関数(OCILobOpen())およびLOBをクローズするための関数(OCILobClose())と、LOBがオープンされているかどうかをテストするための関数(OCILobIsOpen())が提供されています。これらの関数により、一連のLOB操作の開始および終了をマークできるため、LOBのクローズ時に索引の更新など特定の処理が実行できます。

内部LOBでは、オープンされているかどうかの概念は、ロケータではなくLOBに関連しています。ロケータには、LOBの状態に関する情報は格納されません。オープンされている同じLOBを、複数のロケータが指し示すことが可能です。ただし、BFILEについては、オープンは特定のロケータに関連付けられます。したがって、別のロケータを使用して、同じBFILEに対して複数のオープンが実行されることがあります。

アプリケーションで、LOB操作をOCILobOpen()コールとOCILobClose()コールのセットで囲んでいない場合は、LOBが変更されるたびにLOBが暗黙的にオープンおよびクローズされ、それによってLOBの変更に関連付けられているトリガーが起動します。

LOB操作がオープン・コールとクローズ・コールで囲まれていない場合は、LOBの変更時に、LOBの拡張可能な索引がすべて更新されます。このため、索引は常に有効で、任意のタイミングで使用できます。OCILobOpen()コールとOCILobClose()コールで囲まれているLOBが変更された場合、個々のLOBの変更に対してトリガーは起動されません。トリガーはOCILobClose()コールの後にのみ起動されるため、索引が更新されるのはクローズ・コールの後です。したがって、索引はオープン・コールからクローズ・コールまでの間は無効です。OCILobIsOpen()は、内部LOBおよびBFILEとともに使用できます。

トランザクションによってオープンされたすべてのLOBをクローズする前にトランザクションをコミットすると、エラーが戻されます。このエラーが戻されると、LOBはオープンとしてマークされなくなりますが、トランザクションは正常にコミットされます。したがって、トランザクションでLOBデータとLOB以外のデータに対して行われた変更はすべてコミットされます。ただし、ドメイン索引とファンクション索引は更新されません。このエラーが戻された場合は、LOB列のファンクション索引とドメイン索引を再作成してください。

トランザクションがない場合にオープンしているLOBは、セッションの終了前にクローズする必要があります。セッションの終了時にオープンしているLOBがある場合、そのLOBはオープンとしてマークされなくなり、ドメイン索引とファンクション索引は更新されません。このエラーが戻された場合は、LOB列のファンクション索引とドメイン索引を再作成します。

LOBのオープンおよびクローズに関する制限事項

LOBのオープンとクローズに関するメカニズムには、次の制限があります。

  1. アプリケーションでは、トランザクションをコミットする前に、以前にオープンしたLOBをすべてクローズする必要があります。これを行わないと、エラーが発生します。トランザクションがロールバックされた場合は、LOBがクローズされないため、変更とともにオープンしているすべてのLOBが破棄され、関連付けられているトリガーは起動しません。

  2. 内部LOBのオープン数に制限はありませんが、FILEのオープン数には制限があります。『Oracle Databaseリファレンス』のSESSION_MAX_OPEN_FILESパラメータを参照してください。すでにオープンしているロケータを別のロケータに割り当てても、新規LOBのオープンとしてはカウントされません。

  3. 同じトランザクション内で、別のロケータまたは同じロケータを使用して同じ内部LOBを2度オープンまたはクローズすると、エラーになります。

  4. オープンしていないLOBをクローズするとエラーになります。


    注意:


    オープンしているLOBの値をクローズする必要があるトランザクションの定義は、次のいずれかです。
    • SET TRANSACTIONCOMMITの間

    • DATA MODIFYING DMLまたはSELECT...FOR UPDATECOMMITとの間

    • 自律型トランザクション・ブロック内



    関連項目:


LOB読取りおよび書込みコールバック

OCIでは、読取りおよび書込み用コールバック関数をサポートします。次の項では、コールバックの使用方法を詳しく説明します。

ストリーム転送のコールバック・インタフェース

データの挿入または取出しに使用するユーザー定義の読取りおよび書込み用コールバック関数により、LOBをストリーム転送するためのポーリング・メソッドにかわる方法が提供されます。これらの関数はプログラマが実装し、OCILobRead2()コール、OCILobWriteAppend2()コールおよびOCILobWrite2()コールを通じてOCIに登録します。これらのコールバック関数は、必要に応じてOCIでコールします。

コールバックを使用したLOBの読取り

ユーザー定義の読取りコールバック関数は、OCILobRead2()関数を通じて登録されます。コールバック関数には次のプロトタイプが必要です。

CallbackFunctionName ( void *ctxp, CONST void *bufp, oraub8 len, ub1 piece,
                       void **changed_bufpp, oraub8 *changed_lenp);

最初のパラメータのctxpはコールバックのコンテキストで、OCILobRead()ファンクション・コールでOCIに渡されます。コールバック関数がコールされると、ctxpで提供した情報が戻されます(OCIがINの途中でこの情報を使用することはありません)。bufpパラメータは、LOBデータが戻される格納場所へのポインタで、buflはこのバッファの長さを表します。これにより、指定したバッファに読み取られたデータの量がわかります。

元のOCILobRead2()コールで提供したバッファの長さが、サーバーから戻されるデータをすべて格納するのに十分でない場合は、ユーザー定義コールバックがコールされます。この場合、pieceパラメータにより、バッファに戻された情報が最初のピース、次のピースまたは最後のピースのどれであるかが示されます。

パラメータchanged_bufppおよびchanged_lenpをコールバック関数内部で使用して、バッファを動的に変更できます。changed_bufppでは、変更したバッファのアドレスを示す必要があり、changed_lenpでは変更したバッファの長さを示す必要があります。アプリケーションによりバッファが動的に変更されない場合は、changed_bufppおよびchanged_lenpをコールバック関数内部で使用する必要はありません。

次のコード・フラグメントは、OCILobRead2()を使用して読取り用コールバック関数を実装します。次の例では、loblを前もって選択された有効なロケータと想定します。svchpは有効なサービス・ハンドルで、errhpは有効なエラー・ハンドルです。すべてのLOBデータが読み取られるまで、ユーザー定義関数cbk_read_lob()が繰り返しコールされます。

...
oraub8   offset = 1;
oraub8   loblen = 0;
oraub8   byte_amt = 0;
oraub8   char_amt = 0
ub1      bufp[MAXBUFLEN];

sword retval;
byte_amtp = 4294967297;     /* 4 gigabytes plus 1 */

if (retval = OCILobRead2(svchp, errhp, lobl, &byte_amt, &char_amt, offset,
  (void *) bufp, (oraub8) MAXBUFLEN, (void *) 0, OCI_FIRST_PIECE,
  cbk_read_lob, (ub2) 0, (ub1) SQLCS_IMPLICIT))
{
     (void) printf("ERROR: OCILobRead2() LOB.\n");
     report_error();
}
...
sb4 cbk_read_lob(ctxp, bufxp, len, piece, changed_bufpp, changed_lenp)
void       *ctxp;
CONST void *bufxp;
oraub8      len;
ub1         piece;
void       **changed_bufpp;
oraub8      *changed_lenp;
{
    static ub4 piece_count = 0;
    piece_count++;

    switch (piece)
   {
      case OCI_LAST_PIECE:     /*--- buffer processing code goes here ---*/
          (void) printf("callback read the %d th piece\n\n", piece_count);
          piece_count = 0;
          break;
      case OCI_FIRST_PIECE:   /*--- buffer processing code goes here ---*/
          (void) printf("callback read the %d th piece\n", piece_count);
          /* --Optional code to set changed_bufpp and changed_lenp if the
              buffer needs to be changed dynamically --*/
          break;
      case OCI_NEXT_PIECE:   /*--- buffer processing code goes here ---*/
          (void) printf("callback read the %d th piece\n", piece_count);
         /* --Optional code to set changed_bufpp and changed_lenp if the
             buffer needs to be changed dynamically --*/
          break;
      default:
          (void) printf("callback read error: unkown piece = %d.\n", piece);
           return OCI_ERROR;
     }
    return OCI_CONTINUE;
}

コールバックを使用したLOBの書込み

読取りコールバックと同様に、ユーザー定義の書込みコールバック関数がOCILobWrite2()関数を通じて登録されます。コールバック関数には次のプロトタイプが必要です。

CallbackFunctionName ( void *ctxp, void *bufp, oraub8 *lenp, ub1 *piecep,
                        void **changed_bufpp, oraub8 *changed_lenp);

最初のパラメータのctxpはコールバックのコンテキストで、OCILobWrite2()ファンクション・コールでOCIに渡されます。OCIでコールバック関数がコールされると、ctxpで提供した情報が戻されます(OCIがINの途中でこの情報を使用することはありません)。bufpパラメータは記憶領域へのポインタです。このポインタは、OCILobWrite()へのコールで指定されます。

コールで指定するデータをOCILobWrite2()に挿入した後も、残りのデータがユーザー定義コールバックによって挿入されます。コールバックでは、bufpによって示される、記憶域に挿入するデータを指定し、またその長さをbuflpに指定します。さらに、piecepパラメータを使用して、次のピース(OCI_NEXT_PIECE)か最後のピース(OCI_LAST_PIECE)か示します。アプリケーションで提供する記憶域ポインタに対する全責任はプログラマにあるため、割り当てられた格納領域のサイズ以上は書き込まないようにしてください。

パラメータchanged_bufppおよびchanged_lenpをコールバック関数内部で使用して、バッファを動的に変更できます。changed_bufppでは、変更したバッファのアドレスを示す必要があり、changed_lenpでは変更したバッファの長さを示す必要があります。アプリケーションによりバッファが動的に変更されない場合は、changed_bufppおよびchanged_lenpをコールバック関数内部で使用する必要はありません。

次のコード・フラグメントは、OCILobWrite2()を使用して書込み用コールバック関数を実装します。loblを更新用にロックされた有効なロケータと想定します。svchpは有効なサービス・ハンドルで、errhpは有効なエラー・ハンドルです。piecepパラメータにより、アプリケーションが最後のピースを提供していることが示されるまで、ユーザー定義関数cbk_write_lob()は繰り返しコールされます。

...

ub1      bufp[MAXBUFLEN];
oraub8   byte_amt = MAXBUFLEN * 20;
oraub8   char_amt = 0;
oraub8   offset = 1;
oraub8   nbytes = MAXBUFLEN;

/*-- code to fill bufp with data goes here. nbytes should reflect the size and
 should be less than or equal to MAXBUFLEN --*/
if (retval = OCILobWrite2(svchp, errhp, lobl, &byte_amt, &char_amt, offset,
    (void*)bufp, (ub4)nbytes, OCI_FIRST_PIECE, (void *)0, cbk_write_lob,
    (ub2) 0, (ub1) SQLCS_IMPLICIT))
{
   (void) printf("ERROR: OCILobWrite2().\n");
   report_error();
   return;
}
...
sb4 cbk_write_lob(ctxp, bufxp, lenp,  piecep, changed_bufpp, changed_lenp)
void    *ctxp;
void    *bufxp;
oraub8  *lenp;
ub1       *piecep;
void  **changed_bufpp;
oraub8  *changed_lenp;
{
    /*-- code to fill bufxp with data goes here. *lenp should reflect the
        size and should be less than or equal to MAXBUFLEN -- */
    /* --Optional code to set changed_bufpp and changed_lenp if the
        buffer needs to be changed dynamically --*/
    if (this is the last data buffer)
        *piecep = OCI_LAST_PIECE;
    else
        *piecep = OCI_NEXT_PIECE;
    return OCI_CONTINUE;
}

一時LOBのサポート

OCIでは、一時LOBの作成および開放のための関数OCILobCreateTemporary()およびOCILobFreeTemporary()と、LOBが一時LOBであるかどうかを判断する関数OCILobIsTemporary()が提供されています。

一時LOBは、データベース内に永続的に格納されることはありませんが、LOBデータを操作するために、ローカル変数のように動作します。標準(永続)LOB上で動作するOCI関数は、一時LOB上でも使用することができます。

永続LOBと同様に、すべての関数は一時LOBのロケータ上で動作し、実際のLOBデータにはロケータを介してアクセスされます。

一時LOBロケータは、次の型のSQL文への引数として使用できます。

 

注意:


永続ロケータを一時ロケータに選択した場合、一時ロケータは永続ロケータによって上書きされます。この場合、一時LOBは暗黙的には解放されません。ユーザーはSELECT...INTOの前に一時LOBを明示的に解放する必要があります。明示的に解放しなければ、一時LOBは継続時間の終了時まで解放されません。同じLOBを指し示している別の一時ロケータがある場合を除き、元のロケータはSELECT...INTOによって上書きされるため、その一時LOBを指し示すロケータは存在しないことになります。

一時LOBの作成および解放

OCILobCreateTemporary()関数を使用して一時LOBを作成します。この関数に渡されるパラメータには、LOBの継続時間を示す値が含まれています。デフォルトの継続時間は、カレント・セッションの長さです。継続時間の終了時に、すべての一時LOBが削除されます。ユーザーは、OCILobFreeTemporary()関数で一時LOBを明示的に解放することによって、一時LOBの領域を再生できます。一時LOBは、作成されたときは空の状態です。

一時LOBを作成するとき、その一時LOBがサーバーのバッファ・キャッシュに読み取られるかどうかも指定できます。

一時LOBを永続的にするには、OCILobCopy()を使用して、データを一時LOBから永続LOBにコピーします。また、一時LOBをINSERT文のVALUES句で使用したり、UPDATE文内の割当てのソースとして使用したり、あるいは一時LOBを通常の永続LOB属性に割り当てて、オブジェクトをフラッシュできます。一時LOBは、標準LOBの変更に使用する関数と同じ関数を使用して変更できます。

一時LOBの継続時間

OCIでは、いくつかの一時LOB用の事前定義済継続時間、およびアプリケーションでアプリケーション固有の継続時間を定義するために使用できる関数のセットが用意されています。事前定義済の継続時間とその関連属性は、次のとおりです。

  1. コール(OCI_DURATION_CALL)、サーバー側のみ

  2. セッション(OCI_DURATION_SESSION

セッション継続時間は、セッションまたは接続が終了した時点で期限切れになります。コール継続時間は、現行のOCIコールが終了した時点で期限切れになります。

オブジェクト・モードで実行している場合は、アプリケーション固有の継続時間も定義できます。アプリケーション固有の継続時間はユーザー期間とも呼ばれ、OCIDurationBegin()を使用して継続開始時間を指定し、OCIDurationEnd()を使用して継続終了時間を指定することによって定義されます。


注意:


ユーザー定義の継続時間は、アプリケーションがオブジェクト・モードで初期化されている場合にのみ利用できます。

アプリケーション固有の継続時間にはそれぞれ、OCIDurationBegin()で戻される継続時間識別子があり、OCIDurationEnd()がコールされるまで一意であることが保証されます。アプリケーション固有の継続時間は、セッションの継続時間と同じに設定できます。

継続時間の終了時には、その継続時間に関連付けられたすべての一時LOBが解放されます。一時LOBに関連付けられた記述子は、OCIDescriptorFree()コールを使用して明示的に解放する必要があります。

ユーザー定義の継続時間ではネストが可能です。つまり、ある継続時間を別のユーザー期間の子の継続時間として定義できます。親の継続時間は子の継続時間を持つことができます。子の継続時間は各自の子の継続時間を持っています。


注意:


継続時間がOCIDurationBegin()で開始されると、パラメータの1つは親の継続時間の識別子となります。親の継続時間が終了すると、子の継続時間もすべて終了します。

一時LOBの解放

OCIプログラムがSQLまたはPL/SQLからLOBロケータを取得するたびに、一時ロケータかどうかをチェックします。一時ロケータの場合は、アプリケーションがそこで終了するときに、ロケータを解放します。ロケータは、SELECTまたはOUT BIND中にDEFINEから取得できます。一時LOBの継続時間は、クライアント側に受け渡されるときにセッションに対してアップグレードされます。アプリケーションでは、ロケータが次行のロケータで上書きされる前に次の関数を実行する必要があります。

OCILobIsTemporary(env, err, locator, is_temporary);
if(is_temporary)
    OCILobFreeTemporary(svc, err, locator);

ポインタを割り当てる際の注意事項

OCILobLocatorポインタを割り当てるときは、特に注意が必要です。ポインタ割当てにより、LOBの簡単なコピーが作成されます。ポインタの割当て後は、ソースLOBおよびターゲットLOBはデータの同じコピーを指します。これは、割当てを実行するOCILobAssign()またはOCILobLocatorAssign()などのLOB APIを使用するのとは異なります。

APIを使用すると、ロケータは割当て後にデータの個別のコピーを論理的に指します。

一時LOBの場合、ポインタ割当て前に、ターゲットとなるLOBロケータの一時LOBが、OCIFreeTemporary()によって解放されることはプログラマの責任で行ってください。OCILobLocatorAssign()を使用すると、割当てが発生する前にターゲットLOBロケータ変数の元の一時LOB(ある場合)が解放されます。

SQL文の実行において、アウト・バインド変数を再利用する前に、OCIFreeTemporary()コールを使用して、既存のアウト・バインドLOBロケータ・バッファ内の一時LOBを解放することはプログラマの責任で行ってください。


関連項目:

  • 『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』の一時LOBのパフォーマンスのガイドラインに関する項。

  • 一時LOBの最適なパフォーマンスの詳細は、『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』を参照してください。


一時LOBの例

次のコードは、一時LOBの使用例を示しています。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <oci.h>

/* Function Prototype */
static void checkerr (/*_ OCIError *errhp, sword status _*/);
sb4 select_and_createtemp (OCILobLocator *lob_loc,
                           OCIError      *errhp,
                           OCISvcCtx     *svchp,
                           OCIStmt       *stmthp,
                           OCIEnv        *envhp);
/* This function reads in a single video Frame from the print_media table.
Then it creates a temporary lob. The temporary LOB which is created is read
through the CACHE, and is automatically cleaned up at the end of the user's
session, if it is not explicitly freed sooner. This function returns OCI_SUCCESS
if it completes successfully or OCI_ERROR if it fails. */

sb4 select_and_createtemp (OCILobLocator *lob_loc,
                           OCIError      *errhp,
                           OCISvcCtx     *svchp,
                           OCIStmt       *stmthp,
                           OCIEnv        *envhp)
{
  OCIDefine     *defnp1;
  OCIBind       *bndhp;
  text          *sqlstmt;
  int rowind =1;
  ub4 loblen = 0;
  OCILobLocator *tblob;
  printf ("in select_and_createtemp \n");
    if(OCIDescriptorAlloc((void*)envhp, (void **)&tblob,
                          (ub4)OCI_DTYPE_LOB, (size_t)0, (void**)0))
  {
    printf("failed in OCIDescriptor Alloc in select_and_createtemp \n");
    return OCI_ERROR;
 }
  /* arbitrarily select where Clip_ID =1 */
  sqlstmt=(text *)"SELECT Frame FROM print_media WHERE product_ID = 1 FOR UPDATE";
  if (OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4) strlen((char *)sqlstmt),
                     (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT))
  {
      (void) printf("FAILED: OCIStmtPrepare() sqlstmt\n");
      return OCI_ERROR;
  }
  /* Define for BLOB */
  if (OCIDefineByPos(stmthp, &defnp1, errhp, (ub4)1, (void *) &lob_loc, (sb4)0,
             (ub2) SQLT_BLOB, (void *)0, (ub2 *)0, (ub2 *)0, (ub4) OCI_DEFAULT))
  {
    (void) printf("FAILED: Select locator: OCIDefineByPos()\n");
    return OCI_ERROR;
  }
  /* Execute the select and fetch one row */
  if (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
                   (CONST OCISnapshot*) 0, (OCISnapshot*) 0, (ub4) OCI_DEFAULT))
  {
    (void) printf("FAILED: OCIStmtExecute() sqlstmt\n");
    return OCI_ERROR;
  }
  if(OCILobCreateTemporary(svchp, errhp, tblob, (ub2)0, SQLCS_IMPLICIT,
                         OCI_TEMP_BLOB, OCI_ATTR_NOCACHE, OCI_DURATION_SESSION))
  {
    (void) printf("FAILED: CreateTemporary() \n");
    return OCI_ERROR;
  }
  if (OCILobGetLength(svchp, errhp, lob_loc, &loblen) != OCI_SUCCESS)
  {
    printf("OCILobGetLength FAILED\n");
    return OCI_ERROR;
  }
  if (OCILobCopy(svchp, errhp, tblob,lob_loc,(ub4)loblen, (ub4) 1, (ub4) 1))
  {
    printf( "OCILobCopy FAILED \n");
  }
  if(OCILobFreeTemporary(svchp,errhp,tblob))
  {
    printf ("FAILED: OCILobFreeTemporary call \n");
    return OCI_ERROR;
  }
     return OCI_SUCCESS;
}
int main(char *argv, int argc)
{
  /* OCI Handles */
  OCIEnv        *envhp;
  OCIServer     *srvhp;
  OCISvcCtx     *svchp;
  OCIError      *errhp;
  OCISession    *authp;
  OCIStmt       *stmthp;
  OCILobLocator *clob, *blob;
  OCILobLocator *lob_loc;
  int type =1;
  /* Initialize and Logon */
  OCIEnvCreate(&envhp, OCI_DEFAULT, (void *)0, 0, 0, 0,
        (size_t)0, (void *)0);
  (void) OCIHandleAlloc( (void *) envhp, (void **) &errhp, OCI_HTYPE_ERROR,
                          (size_t) 0, (void **) 0);
  /* server contexts */
  (void) OCIHandleAlloc( (void *) envhp, (void **) &srvhp, OCI_HTYPE_SERVER,
                         (size_t) 0, (void **) 0);
   /* service context */
  (void) OCIHandleAlloc( (void *) envhp, (void **) &svchp, OCI_HTYPE_SVCCTX,
                         (size_t) 0, (void **) 0);
    /* attach to Oracle */
  (void) OCIServerAttach( srvhp, errhp, (text *)"", strlen(""), 0);
    /* set attribute server context in the service context */
  (void) OCIAttrSet ((void *) svchp, OCI_HTYPE_SVCCTX,
                     (void *)srvhp, (ub4) 0,
                     OCI_ATTR_SERVER, (OCIError *) errhp);
   (void) OCIHandleAlloc((void *) envhp,
                        (void **)&authp, (ub4) OCI_HTYPE_SESSION,
                        (size_t) 0, (void **) 0);
   (void) OCIAttrSet((void *) authp, (ub4) OCI_HTYPE_SESSION,
                    (void *) "scott", (ub4)5,
                    (ub4) OCI_ATTR_USERNAME, errhp);
  (void) OCIAttrSet((void *) authp, (ub4) OCI_HTYPE_SESSION,
                    (void *) "password", (ub4) 5,
                    (ub4) OCI_ATTR_PASSWORD, errhp);
  /* Begin a User Session */
  checkerr(errhp, OCISessionBegin ( svchp,  errhp, authp, OCI_CRED_RDBMS,
                                    (ub4) OCI_DEFAULT));
  (void) OCIAttrSet((void *) svchp, (ub4) OCI_HTYPE_SVCCTX,
                    (void *) authp, (ub4) 0,
                    (ub4) OCI_ATTR_SESSION, errhp);
  /* ------- Done loggin in ----------------------------------*/
   /* allocate a statement handle */
  checkerr(errhp, OCIHandleAlloc( (void *) envhp, (void **) &stmthp,
                             OCI_HTYPE_STMT, (size_t) 0, (void **) 0));
  checkerr(errhp, OCIDescriptorAlloc((void *)envhp, (void **)&lob_loc,
                   (ub4) OCI_DTYPE_LOB, (size_t) 0, (void **) 0));
  /* Subroutine calls begin here */
  printf("calling select_and_createtemp\n");
  select_and_createtemp (lob_loc, errhp, svchp,stmthp,envhp);
  return 0;
}
void checkerr(errhp, status)
OCIError *errhp;
sword status;
{
  text errbuf[512];
  sb4 errcode = 0;
  switch (status)
  {
  case OCI_SUCCESS:
    break;
  case OCI_SUCCESS_WITH_INFO:
    (void) printf("Error - OCI_SUCCESS_WITH_INFO\n");
    break;
  case OCI_NEED_DATA:
    (void) printf("Error - OCI_NEED_DATA\n");
    break;
  case OCI_NO_DATA:
    (void) printf("Error - OCI_NODATA\n");
    break;
  case OCI_ERROR:
    (void) OCIErrorGet((void *)errhp, (ub4) 1, (text *) NULL, &errcode,
                        errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR);
    (void) printf("Error - %.*s\n", 512, errbuf);
    break;
  case OCI_INVALID_HANDLE:
    (void) printf("Error - OCI_INVALID_HANDLE\n");
    break;
  case OCI_STILL_EXECUTING:
    (void) printf("Error - OCI_STILL_EXECUTE\n");
    break;
  case OCI_CONTINUE:
    (void) printf("Error - OCI_CONTINUE\n");
    break;
  default:
    break;
  }
}

LOBデータ、長さおよびチャンク・サイズのプリフェッチ

小さいLOBのOCIアクセスを改善するために、LOBデータをプリフェッチしてキャッシュする間にロケータもフェッチできます。これは内部LOB、一時LOBおよびBFILEに適用されます。アプリケーションで実行できるステップは、次のとおりです。

  1. セッション・ハンドルのOCI_ATTR_DEFAULT_LOBPREFETCH_SIZE属性を設定します。この属性の値は、LOBロケータのデフォルトのプリフェッチ・データ・サイズを示します。これにより、セッション中にフェッチされる全LOBロケータのプリフェッチが可能になります。この属性のデフォルト値は0(LOBデータのプリフェッチなし)です。このオプションにより、アプリケーション開発者は定義ハンドルごとにプリフェッチLOBサイズを設定する必要がなくなります。この属性を設定するか、または(ステップ3で)OCI_ATTR_LOBPREFETCH_SIZEを設定できます。

  2. 実行する文の準備ステップと定義ステップを実行します。

  3. 必要な場合は、定義ハンドルのOCI_ATTR_LOBPREFETCH_SIZE属性を設定して、フェッチするLOBロケータのデフォルト・プリフェッチ・サイズを上書きできます。このオプション属性では、特定の列からフェッチされるロケータのプリフェッチ・サイズを制御できます。

  4. OCI_ATTR_LOBPREFETCH_LENGTH属性を、プリフェッチするLOBの長さおよびチャンク・サイズに設定します。

  5. 文を実行します。

  6. 個別のLOBロケータを指定してOCILobRead2()またはOCILobArrayRead()をコールします。OCIによりプリフェッチ・バッファからデータが取得され、必要な文字変換が実行され、データがLOB読取りバッファにコピーされます(LOBセマンティクスは変更されません)。要求されたデータがプリフェッチ・バッファよりも大きい場合は、追加のラウンドトリップが必要になります。

  7. OCILobGetLength2()およびOCILobGetChunkSize()をコールして、サーバーへのラウンドトリップなしで長さとチャンク・サイズを取得します。

プリフェッチ・サイズは、BLOBおよびBFILEの場合はバイト数、CLOBの場合は文字数であることに注意してください。

次のコード・フラグメントに、前述のステップを示します。

...
ub4 default_lobprefetch_size = 2000;                  /* Set default size to 2K */
...
/* set lob prefetch attribute to session */
OCIAttrSet (sesshp, (ub4) OCI_HTYPE_SESSION,
            (void *)&default_lobprefetch_size,               /* attribute value */
            0,                      /* attribute size; not required to specify; */
            (ub4) OCI_ATTR_DEFAULT_LOBPREFETCH_SIZE,
            errhp);
...
/* select statement */
char *stmt = "SELECT lob1 FROM lob_table";
...
/* declare and allocate LOB locator */
OCILobLocator * lob_locator;
lob_locator = OCIDescriptorAlloc(..., OCI_DTYPE_LOB, ...);

OCIDefineByPos(..., 1, (void *) &lob_locator, ..., SQLT_CLOB, ...);
...
/* Override the default prefetch size to 4K */
ub4 prefetch_size = 4000;
OCIAttrSet (defhp,  OCI_HTYPE_DEFINE,
            (void *) &prefetch_size                             /* attr value */,
            0                  /* restricting prefetch size to be ub4 max val */,
            OCI_ATTR_LOBPREFETCH_SIZE                            /* attr type */,
            errhp);
...
/* Set prefetch length attribute */
boolean prefetch_length = TRUE;
OCIAttrSet( defhp,  OCI_HTYPE_DEFINE,
            (dvoid *) &prefetch_length  /* attr value */,
            0,
            OCI_ATTR_LOBPREFETCH_LENGTH  /* attr type */,
            errhp );
...
/* execute the statement. 4K of data for the LOB is read and
 * cached in descriptor cache buffer.
 */
OCIStmtExecute (svchp, stmthp, errhp,
                1,               /* iters */
                0,               /* row offset */
                NULL,            /* snapshot IN */
                NULL,            /* snapshot out */
                OCI_DEFAULT);    /* mode */
...
oraub8 char_amtp = 4000;
oraub8 lob_len;
ub4 chunk_size;

/* LOB chunk size, length, and data are read from cache. No round trip. */

OCILobGetChunkSize (svchp, errhp, lob_locator, &chunk_size);

OCILobGetLength2(svchp, errhp, lob_locator, &lob_len );

OCILobRead2(svchp, errhp, lob_locator, NULL, &char_amtp, ...);
...

プリフェッチ・キャッシュの割当て: 記述子用のプリフェッチ・キャッシュ・バッファは、LOBロケータのフェッチ中に割り当てられます。割当てバッファ・サイズは、定義ハンドルのOCI_ATTR_LOBPREFETCH_SIZE属性により決定されます。この属性のデフォルト値は、セッション・ハンドルのOCI_ATTR_DEFAULT_LOBPREFETCH_SIZE属性の値で示されます。キャッシュ・バッファが割当済の場合は、必要に応じてサイズ変更されます。

次の2つのLOB APIの場合、ソース・ロケータにキャッシュされたデータがあると、宛先ロケータのキャッシュが割り当てられるかサイズ変更され、キャッシュ・データがソースから宛先にコピーされます。

記述子用に割り当てられたキャッシュ・バッファ・メモリーは、記述子自体が解放されるときに解放されます。

プリフェッチ・キャッシュの無効化: 記述子用のキャッシュは、ロケータを使用してLOBデータが更新されるときに無効化されます。これは、そのキャッシュがデータの読取りに使用されなくなり、ロケータでの次のOCILobRead()コールでラウンドトリップが発生することを意味します。

次のLOB APIにより、使用された記述子用のプリフェッチ・キャッシュが無効化されます。

次のLOB APIにより、宛先LOBロケータ用のキャッシュが無効化されます。

パフォーマンス・チューニング: プリフェッチ・バッファのサイズは、平均LOBサイズとクライアント側のメモリーに基づいて決定する必要があります。大量のデータがプリフェッチされる場合は、メモリーの可用性を確認する必要があります。データ・フェッチに伴うコストの方がサーバーへのラウンドトリップに伴うコストよりも大きいため、大きいLOBをプリフェッチする場合には、大幅なパフォーマンス向上は期待できない可能性があります。

このLOBプリフェッチ機能を活用できるように、LOBデータ・サイズを適正に考慮する必要があります。パラメータは、アプリケーション設計の一環です。そのため、パラメータ値の変更が必要になった場合は、アプリケーションを再作成する必要があります。

アップグレード: リリース11.1より前のサーバー、リリース11.1以降のサーバーに対するリリース11.1より前のクライアントには、LOBプリフェッチを使用できません。リリース11.1より前のサーバーをリリース11.1以降のクライアントに対して使用している場合、OCISetAttr()からエラー、または、この機能がサーバーでサポートされていないという旨のエラー・メッセージが戻されます。

SecureFile LOBのオプション

Oracle SecureFiles(Oracle Database 11gリリース1で導入されたSTORE AS SECUREFILEオプションを使用するLOB)の場合、CREATE TABLEおよびALTER TABLE文にSQLパラメータDEDUPLICATEを指定できます。これにより、LOB列の複数行で同一の全LOBデータが同じデータ・ブロックを共有するように指定して、ディスク領域を節約できます。この機能をオフにするには、KEEP_DUPLICATESを使用します。次の各オプションも、SECUREFILEとともに使用されます。

パラメータCOMPRESSでは、LOB圧縮をオンにします。NOCOMPRESSでは、LOB圧縮をオフにします。

パラメータENCRYPTでは、LOB暗号化をオンにして、オプションで暗号化アルゴリズムを選択します。NOENCRYPTでは、LOB暗号化をオフにします。各LOB列には、他のLOB列または非LOB列の暗号化に関係なく、独自の暗号化仕様を設定できます。有効なアルゴリズムは、3DES168AES128AES192およびAES256です。

リリース11.1より前のLOBのパラダイムがデフォルトです。これは、オプションSTORE AS BASICFILEでも明示的に設定されます。

SECUREFILE機能とともに、次のSQL文、PL/SQLパッケージおよびOCI関数を使用します。


関連項目:

  • 関連SQL関数の詳細とPL/SQLパッケージの相互参照およびSecureFilesへの移行については、『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』を参照してください。

  • 「OCILobGetOptions()」

  • 「OCILobSetOptions()」