9 LOBおよびBFILEの操作
この章では、LOBおよびBFILEの操作について説明します。
この章には次のトピックが含まれます:
9.1 LOBでのOCI関数の使用について
OCIには、データベース内のラージ・オブジェクト(Large Object: LOB)で操作を実行するための一連の関数があります。
永続LOB (BLOB
、CLOB
、NCLOB
)はデータベースの表領域に格納されており、領域の最適化とアクセスの効率化を実現します。これらのLOBは、Oracle Databaseのトランザクションを完全にサポートしています。BFILE
とは、データベース表領域外のサーバーのオペレーティング・システム・ファイルに格納された大型のデータ・オブジェクトのことです。
また、OCIは一時LOBもサポートしており、これは、LOBデータ上で操作するローカル変数のように使用することができます。
BFILE
は読取り専用です。バイナリのBFILE
のみをサポートしています。
Oracle Database 12cリリース2 (12.2)以上では、ほとんどのLOB関数は、アプリケーション・コンティニュイティをサポートしています。
Oracle Database 12c
リリース2 (12.2)以上では、OCI LOB APIによってリモートLOB (CLOB、BLOB)での分散操作がサポートされます(BFILES用のOCI LOB APIを除く)。これには、以前のリリースではエラーを戻していたリモートLOBロケータを選択する一定の問合せのサポートが含まれます。唯一の制限は、2つのロケータを受け入れるすべてのLOB APIで、両方のLOBが1つのデータベースに存在している必要があることです。次のLOB関数では、リモート・ロケータが渡されるとエラーがスローされます: OCILobAssign()
、OCILobLocatorAssign()
、OCILobEnableBuffering()
、OCILobDisableBuffering()
、OCILobFlushBuffer()
、OCILobArrayRead()
、OCILobArrayWrite()
およびOCILobLoadFromFile2()
。
関連項目:
-
LOBの使用方法を示したコード例は、「OCIデモ・プログラム」を参照してください
-
特定のLOBコードのサンプルは、
$ORACLE_HOME/rdbms/demo/lobs/oci/
を参照してください。 -
DBMS_LOB
パッケージは、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください -
完全なリストについては、「OCIのアプリケーション・コンティニュイティがフェイルオーバーできる場合」を参照してください。
-
互換性のために一部の非推奨のLOB関数でもアプリケーション・コンティニュイティがサポートされています。詳細は、「非推奨のLOB関数」を参照してください。
9.2 永続LOBの作成と変更について
LOBインスタンスは永続的(データベースに格納)または一時的(アプリケーションの有効範囲内のみに存在)のいずれかである可能性があります。
永続LOBと永続オブジェクトの概念を混同しないでください。
永続LOBの作成および変更には、次の2つの方法があります。
-
データ・インタフェースの使用
文字データを
CLOB
列に挿入、またはRAW
データをBLOB
列に直接挿入すると、LOBを作成できます。SQLのUPDATE
文を使用するか、文字データをCLOB
列にバインドするか、またはRAW
データをBLOB
列にバインドすると、LOBを変更することもできます。リモート・サーバーとローカル・サーバーがいずれもOracle Database 10gリリース2以上であるので、リモートLOBの(dblinkを介した)挿入、更新および選択がサポートされます。データ・インタフェースでは、最大2GB -1、つまり
sb4
データ型の最大サイズまでのデータ・サイズのみサポートされます。 -
LOBロケータの使用
内部LOBを新規作成するには、
OCIDescriptorAlloc()
を使用して新規のLOBロケータを初期化してから、OCIAttrSet()
をコールして(OCI_ATTR_LOBEMPTY
属性を使用して)空に設定し、次に、そのロケータをINSERT
文でプレースホルダにバインドします。この処理により、LOB列または属性がある表に空のロケータを挿入します。次に、SELECT
...FOR
UPDATE
操作をこの行で実行してロケータを取得し、OCI LOB関数の1つを使用してロケータに書き込みます。ノート:
LOB列または属性を変更(書込み、コピー、切捨てなど)するには、そのLOBが含まれている行をロックする必要があります。そのためには、操作を実行する前に
SELECT...FOR UPDATE
文を使用してロケータを選択します。
LOB書込みコマンドを正常終了するには、トランザクションをオープンしておく必要があります。データの書込み前にトランザクションをコミットする場合は、コミットによってトランザクションがクローズされるため、(SELECT...FOR UPDATE
文の再発行などにより)行を再ロックする必要があります。
関連項目:
-
詳細と例は、『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』 の永続LOBのデータ・インタフェースに関する章を参照してください
-
INSERT
およびUPDATE
の使用方法および使用例は、「LOBデータのバインドについて」を参照してください
9.3 表内のBFILEとオペレーティング・システム・ファイルの関連付けについて
INSERT
文でBFILENAME
関数を使用すると、外部サーバー側(オペレーティング・システム)ファイルと表内のBFILE
列または属性を関連付けることができます。
UPDATE
文でBFILENAME
を使用して、BFILE
の列または属性を別のオペレーティング・システム・ファイルに関連付けます。OCILobFileSetName()
を使用して、表内のBFILE
をオペレーティング・システム・ファイルに関連付けることもできます。通常、BFILENAME
はINSERT
またはUPDATE
文内でバインド変数なしで使用され、OCILobFileSetName()
がバインド変数に使用されます。
関連項目:
-
BFILENAME
関数の詳細は、『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』 を参照してください
9.4 オブジェクトのLOB属性
OCIアプリケーションでは、OCIObjectNew()
関数を使用して、LOB属性を持つ永続オブジェクトまたは一時オブジェクトを作成することができます。
関連項目:
9.4.1 オブジェクトのLOB属性への書込み
OCIを使用して、LOB属性を持つ新規の永続オブジェクトを作成したり、そのLOB属性への書込みができます。
LOBロケータを使用するときは、アプリケーションでは次のステップに従います。
LOB属性に書き込むには、もう1つ方法があります。データ・インタフェースを使用すると、CLOB
属性の文字データ、またはBLOB
属性のRAW
データのバインドまたは定義ができます。
関連項目:
-
オブジェクトの詳細は、「OCIオブジェクト・リレーショナル・プログラミング」およびそれ以降の章を参照してください
-
INSERT
文およびUPDATE
文の使用方法および使用例は、「LOBデータのバインドについて」を参照してください -
SELECT
文の使用方法および使用例は、「LOBデータの定義について」を参照してください
9.4.2 LOB属性を持つ一時オブジェクト
アプリケーションでは、OCIObjectNew()
をコールして、内部LOB(BLOB
、CLOB
、NCLOB
)属性を持つ一時オブジェクトを作成できます。
ただし、LOB属性を持つ一時オブジェクトは現在サポートされていないため、読取りや書込みなどの、LOB属性での操作は実行できません。一時内部LOB型を作成するためのOCIObjectNew()
コールは失敗しませんが、アプリケーションでは、この一時LOBでLOB操作を使用することはできません。
ただし、アプリケーションでは、BFILE
属性を持つ一時オブジェクトを作成し、BFILE
属性を使用して、サーバーのファイル・システムに格納されているファイルからデータを読み取ることができます。アプリケーションでは、OCIObjectNew()
をコールして、一時BFILE
を作成できます。
関連項目:
9.5 LOBの配列インタフェース
OCI配列インタフェースは、他のデータ型と同様に、LOBに対しても使用できます。
配列インタフェースを使用するには、次の2つの方法があります。
-
データ・インタフェースの使用
文字データの配列を
CLOB
列に対して、またはRAW
データの配列をBLOB
列に対してバインドまたは定義できます。配列のバインドおよび定義インタフェースを使用すると、LOBを含む複数の行をサーバーへの1回のラウンドトリップで挿入および選択できます。 -
LOBロケータの使用
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], ...);
関連項目:
-
INSERT
文およびUPDATE
文の使用方法および使用例は、「LOBデータのバインドについて」を参照してください -
SELECT
文の使用方法および使用例は、「LOBデータの定義について」を参照してください
9.6 4GBより大きいサイズのLOBの使用について
OCIのOracle Database 10gリリース1からは、4GBより大きいサイズのLOBをサポートする関数が導入されました。この新機能は、4GBより小さいLOBの新規アプリケーションでも使用できます。
Oracle Databaseを使用すると、データベースのブロック・サイズとは異なるブロック・サイズを持つ表領域を作成できます。LOBの最大サイズは、表領域のブロック・サイズに応じて異なります。LOBが格納される表領域のブロック・サイズにより、LOB記憶域のパラメータであるCHUNK
の値が制御されます。LOB列を作成する場合、CHUNK
の値を指定できます。これは、LOBの操作用に割り当てるバイト数です。この値は、表領域ブロック・サイズの倍数である必要があります。そうでない場合、Oracle Databaseによって次の倍数に切り上げられます。(表領域のブロック・サイズがデータベースのブロック・サイズと同じ場合、CHUNK
は、データベースのブロック・サイズの倍数でもあります。)CHUNK
のデフォルト・サイズは、1つの表領域ブロックのサイズと同じで、最大値は32KBです。
このマニュアルでは、4GBは4GB–1、または4,294,967,295バイトと定義します。LOB(永続または一時)の最大サイズは、(4GB–1)×(CHUNK
)です。LOBの最大サイズは、8TBから128TBの範囲です。
たとえば、データベースのブロック・サイズが32KBで、標準外の8KBのブロック・サイズで表領域を作成するとします。さらに、LOB列を持つ表を作成し、CHUNK
サイズを16KB (表領域のブロック・サイズである8KBの倍数)に指定するとします。この場合、この列のLOBの最大サイズは(4GB-1)×16KBです。
BFILE
の最大サイズは、ご使用のオペレーティング・システムで許容される最大ファイル・サイズとUB8MAXVAL
のどちらか小さい方となります。
以前のLOB関数ではub4
を一部のパラメータのデータ型として使用し、ub4
データ型では最大4GBしか保持できません。新しい関数では、8バイト長のパラメータ、oraub8
を使用し、これはoratypes.h
で定義されるデータ型です。コンパイラとオペレーティング・システムに応じて、データ型oraub8
およびorasb8
は該当する64ビット固有のデータ型にマップされます。厳密なANSIオプションを使用して32ビット・モードでコンパイルする場合、マクロを使用してoraub8
およびorasb8
を定義することはできません。
OCILobGetChunkSize()
は、利用可能なチャンク・サイズをBLOB
、CLOB
およびNCLOB
に対してバイト数で戻します。チャンクに格納されるバイト数は、内部記憶域のオーバヘッドにより、実際にはCHUNK
パラメータのサイズより小さくなります。関数OCILobGetStorageLimit()
により、現行インストールにおける内部LOBの最大サイズがバイト数で戻されます。
ノート:
Oracle Databaseでは、どのようなプログラム環境においても、4GBを超えるBFILE
はサポートされません。ご使用のオペレーティング・システムのその他のファイル・サイズ制限もBFILE
に適用されます。
9.6.1 増加した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
パラメータはCLOB
とNCLOB
では基本設定となり、byte_amtp
パラメータは、char_amtp
が0 (ゼロ)の場合のみ、入力とみなされます。CLOB
およびNCLOB
の出力時には、byte_amtp
とchar_amtp
の両方のパラメータに値が入ります。BLOB
およびBFILE
の場合、入力時も出力時もchar_ampt
パラメータは無視されます。
問題点: OCILobRead2()
には、ポーリング・モードを示すためのフラグがありません。このため、ユーザーは「100バイトのバッファがあります。できるかぎり使用してください。」と指示するのが困難になります。以前は、総量に対して指定する文字数を見積もる必要がありました。あまり多く見積もりすぎると、意図せずポーリング・モードに移行されていました。このように、ユーザー・コードによりポーリング・モードでトラップされる場合があり、以降のOCIコールがすべてブロックされてしまいます。
解決策: このコールでは、piece
を入力パラメータとして取り、OCI_ONE_PIECE
が渡された場合は、byte_amtp
パラメータまたはchar_amtp
パラメータで指定した値がバッファ長より大きくても、バッファを可能なかぎり埋めて出る必要があります。bufl
の値を使用して、読み取るバイトの最大量を指定します。
問題点: ポーリング・モードでLOB書込みをコールした後は、ポーリングの終了までに実際にフェッチされる文字数またはバイト数をユーザーは認識できません。
解決策: ポーリング・モードでの各コール後に、byte_amtp
およびchar_amtp
の両パラメータを更新してください。
問題点: コールバックを使用した、ストリーム・モードでの読取り時または書込み時には、ユーザーはデータの各ピースに対して同じバッファを使用する必要があります。
解決策: コールバック関数には、バッファおよびバッファ長を指定する2つの新規パラメータを含めてください。コールバック関数で、バッファ・パラメータをNULL
に設定すると、以前の動作に従います(すべてのピースに対する最初のコールで渡されるデフォルト・バッファを使用)。
9.6.2 互換性および移行
既存のOCIプログラムを拡張して、4GBより大きい大容量のLOBデータを処理できます。
表9-1に、互換性の問題点をまとめます(「旧」とは、Oracle Database 10gリリース1より前のリリースを指し、「NA」とは該当なしを意味します)。
表9-1 LOB関数の互換性および移行
LOB関数 | 旧クライアント/新規または旧サーバー(1) | 新規クライアント/旧サーバー | 新規クライアント/新規サーバー |
---|---|---|---|
脚注 2NA |
ピース・サイズおよびオフセットが4GB未満であればOK。 |
OK |
|
NA |
ピース・サイズおよびオフセットが4GB未満であればOK。 |
OK |
|
NA |
LOBサイズ、ピース・サイズ(量)およびオフセットが4GB未満であればOK。 |
OK |
|
OK (制限は4GB)。 |
OK |
OK (制限は4GB)。 |
|
NA |
ピース・サイズおよびオフセットが4GB未満であればOK。 |
OK |
|
OK (制限は4GB)。 |
OK |
OK (制限は4GB)。 |
|
NA |
OK |
OK |
|
OK (制限は4GB)。 |
OK |
OK (LOBサイズが > 4GBの場合は |
|
NA |
LOBサイズ、ピース・サイズ(量)およびオフセットが4GB未満であればOK。 |
OK |
|
OK (制限は4GB)。 |
OK |
OK (制限は4GB)。 |
|
NA |
LOBサイズ、ピース・サイズ(量)およびオフセットが4GB未満であればOK。 |
OK |
|
OK (制限は4 GB)。 新規サーバーを使用した場合: 4GB以上の量を4GB未満のオフセットから読み取ろうとすると、 ノート:
|
OK |
OK。 4GB以上の量を4GB未満のオフセットから読み取ろうとすると、 ノート:
|
|
NA |
OK |
OK |
|
OK (制限は4GB)。 |
OK |
OK (制限は4GB)。 |
|
NA |
LOBサイズ、ピース・サイズ(量)およびオフセットが4GB未満であればOK。 |
OK |
|
OK (制限は4GB)。 新規サーバーを使用した場合: 4GB以上の量を(4GB未満のオフセットから)書き込むと、 ノート: 4GB –1までの量のデータにより、10GBのLOBを4GB –1までのオフセットから更新しても、エラーとしてフラグは立てられません。 |
OK |
OK 4GB以上の量を(4GB未満のオフセットから)書き込むと、*amtpの戻り値がオーバーフローするため、 ノート: 4GB –1までの量のデータにより、10GBのLOBを4GB –1までのオフセットから更新しても、エラーとしてフラグは立てられません。 |
|
NA |
LOBサイズおよびピース・サイズが4GB未満であればOK。 |
OK |
|
OK (制限は4GB)。 新規サーバーを使用した場合: 4GB以上のデータを追加すると、 |
OK |
OK (制限は4GB)。 4GB以上のデータを追加すると、 |
|
NA |
エラー |
OK |
脚注 1 「旧」とは、Oracle Database 10gリリース1より前のリリースを指します。
脚注 2
NAは、該当なしを意味します。
現行サーバーと現行クライアントを使用する場合は、「2」で終わる関数を使用してください。非推奨の関数を「2」で終わる関数と併用すると、OCILobWrite2()
を使用して書き込まれたデータが4GBより大きいときに、アプリケーションでOCILobRead()
を使用してそれが読み取られると、データの一部しか取得されない(コールバック関数が使用されていない場合)など、予期せぬ状況になる可能性があります。サイズが4GBを超えていて、非推奨の関数が使用されると、ほとんどの場合、アプリケーションでエラー・メッセージを受け取ります。ただし、サイズが4GBより小さいLOBに対して非推奨の関数を使用する場合、問題は発生しません。
9.7 OCIのLOB関数およびBFILE関数
データへのオフセットを伴うすべてのLOB操作では、オフセットは1から始まります。OCILobCopy2()
、OCILobErase2()
、OCILobLoadFromFile2()
およびOCILobTrim2()
などのLOB操作の場合、amount
パラメータは、クライアント側の文字セットにかかわらず、CLOB
とNCLOB
の文字数です。
これらのLOB操作は、サーバー上のLOBデータの量を参照します。クライアント側の文字セットが可変幅の場合は、次の一般的な規則がLOBコールのamount
パラメータとoffset
パラメータに適用されます。
-
amount
-amountパラメータがサーバー側のLOBを参照する場合、amountは文字数です。amountパラメータがクライアント側のバッファを参照する場合、amountはバイト数です。 -
offset
- クライアント側の文字セットが可変幅かどうかにかかわらず、offsetパラメータは常にCLOB
またはNCLOB
の場合は文字数、BLOB
またはBFILE
の場合はバイト数です。
これらの一般的な規則の例外は、特定のLOBコールの説明で示してあります。
9.7.1 LOBの読取り/書込みパフォーマンスの向上について
LOBの読取り/書込みパフォーマンスを向上する方法について説明します。
9.7.1.1 LOBに対するデータ・インタフェースの使用について
CLOB
列の文字データまたはBLOB
列のRAW
データをバインドまたは定義できます。
ここでは、複数回のラウンドトリップを必要とする従来のLOBインタフェースとは対照的に、LOBを挿入または選択する際に必要なラウンドトリップは1回のみです。
関連項目:
-
INSERT
文およびUPDATE
文の使用方法および使用例は、「LOBデータのバインドについて」を参照してください -
SELECT
文の使用方法および使用例は、「LOBデータの定義について」を参照してください
9.7.1.2 OCILobGetChunkSize()の使用について
OCILobGetChunkSize()
は、利用可能なチャンク・サイズをBLOB
、CLOB
およびNCLOB
に対してバイト数で戻します。
OCILobGetChunkSize()
コールを使用すれば、BasicFile LOBに関するLOBの読取りおよび書込み操作のパフォーマンスを改善できます。サイズが利用可能なチャンク・サイズの倍数で、操作がチャンクの境界から始まるBasicFile LOBデータで読取りまたは書込みが行われると、パフォーマンスが向上します。OCILobGetChunkSize()
の位置合せを使用して、SecureFile LOBを読取りまたは書込みする必要はありません。
OCILobGetChunkSize()
のコールにより、LOBの利用可能なチャンク・サイズが戻されるため、アプリケーションは、同じチャンクに対する複数のLOB書込みコールを発行するかわりに、チャンク全体に対する一連の書込み操作をバッチ処理できます。
9.7.1.3 OCILobWriteAppend2()の使用について
OCIでは、LOBの末尾へのデータの書込みをより効率的にするためのショートカットが提供されています。
OCILobWriteAppend2()
コールにより、最初にOCILobGetLength2()
をコールしてOCILobWrite2()
操作の開始点を決定しなくても、データをLOBの末尾に追加できます。OCILobWriteAppend2()
では、両方のステップが行われます。
9.7.1.4 OCILobArrayRead()およびOCILobArrayWrite()の使用について
OCILobArrayRead()
を使用して、複数のLOBロケータに対してLOBデータを読み取り、OCILobArrayWrite()
を使用して、複数のLOBロケータに対してLOBデータを書き込むことにより、パフォーマンスを改善できます。
これら関数は、Oracle Database 10gリリース2で導入され、これらの操作のラウンドトリップ数を減らします。
関連項目:
-
これらの関数をコールバック関数とともにピース単位モードで使用する方法の詳細とコード例は、『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』のLOB配列読取りに関する項とLOB配列書込みに関する項を参照してください
9.7.2 LOBバッファリング関数
これらのLOB関数は非推奨です。これらのLOBバッファリング関数のかわりに、LOBプリフェッチ機能を使用してください。
OCIには、内部LOB値の小さな読取りと書込みのために、LOBのバッファリングを制御する次のコールがあります。
-
OCILobEnableBuffering()
-
OCILobDisableBuffering()
-
OCILobFlushBuffer()
これらの関数により、内部LOB (BLOB
、CLOB
、NCLOB
)を使用するアプリケーションでは、クライアント側のバッファで小さな読取りと書込みをバッファできます。これにより、ネットワーク・ラウンドトリップの回数とLOBのバージョンを削減でき、LOBのパフォーマンスが大幅に向上します。
関連項目:
-
LOBバッファの詳細は、『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』のLOB APIの使用に関する章を参照してください。
-
各関数に必要なサーバー・ラウンドトリップ回数のリストは、「LOB関数のラウンドトリップ」を参照してください
9.7.3 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およびBFILEs
とともに使用できます。
トランザクションでオープンしたすべてのLOBをクローズする前に、そのトランザクションをコミットしようとすると、エラーが発生します。エラーが戻された場合、それ以降LOBはオープンとしてマークは付けられませんが、トランザクションのコミットは正常に行われます。このため、トランザクション内でLOBおよび非LOBデータに対して行われた変更はすべてコミットされますが、ドメイン索引およびファンクション索引は更新されません。これが起こった場合は、LOB列のファンクション索引とドメイン索引を再作成します。
トランザクションがない場合にオープンしているLOBは、セッションの終了前にクローズする必要があります。セッションの終了時にオープンしているLOBがある場合、そのLOBはオープンとしてマークされなくなり、ドメイン索引とファンクション索引は更新されません。これが起こった場合は、LOB列のファンクション索引とドメイン索引を再作成します。
この項には次のトピックが含まれます。「LOBのオープンおよびクローズに関する制限事項」。
9.7.3.1 LOBのオープンおよびクローズに関する制限事項
LOBのオープンおよびクローズに関する制限事項について説明します。
LOBのオープンおよびクローズのメカニズムには、次の制限があります。
-
トランザクションをコミットする前に、アプリケーションでオープンしているすべてのLOBをクローズする必要があります。さもないとエラーが発生します。トランザクションをロールバックする場合、すべてのオープンLOBは、行われた変更とともに廃棄されます。LOBがクローズされないために、関連付けられたトリガーは起動されません。
-
内部LOBのオープン数に制限はありませんが、
SESSION_MAX_OPEN_FILES
パラメータによって決定されるファイルのオープン数には制限があります。すでにオープンしているロケータを別のロケータに割り当てても、新規LOBのオープンとしてはカウントされません。 -
同じトランザクション内で、別のロケータまたは同じロケータを使用して同じ内部LOBを2度オープンまたはクローズすると、エラーになります。
-
オープンしていないLOBをクローズするとエラーになります。
ノート:
オープンLOB値をクローズする必要があるトランザクションの定義は、次のいずれかとなります。
-
SET TRANSACTION
およびCOMMIT
の間 -
DATA
MODIFYING
DML
またはSELECT
... FOR UPDATE
とCOMMIT
との間。 -
自律型トランザクション・ブロック内
-
関連項目:
-
『Oracle Databaseリファレンス』の
SESSION_MAX_OPEN_FILES
パラメータに関する項を参照してください -
オンライン・デモ・プログラムのOCILobOpen()コールおよびOCILobClose()コールの使用例は、「OCIデモ・プログラム」を参照してください
9.7.4 LOB読取りおよび書込みコールバック
OCIでは、読取りおよび書込み用コールバック関数をサポートします。
9.7.4.1 ストリーム転送のコールバック・インタフェース
データの挿入または取出しに使用するユーザー定義の読取りおよび書込み用コールバック関数により、LOBをストリーム転送するためのポーリング・メソッドにかわる方法が提供されます。
これらの関数はプログラマが実装し、OCILobRead2()
コール、OCILobWriteAppend2()
コールおよびOCILobWrite2()
コールを通じてOCIに登録します。これらのコールバック関数は、必要に応じてOCIでコールします。
9.7.4.2 コールバックを使用したLOBの読取り
ユーザー定義の読取りコールバック関数は、OCILobRead2()
関数を通じて登録されます。
コールバック関数には次のプロトタイプが必要です。
CallbackFunctionName
( void *ctxp, CONST void *bufp, oraub8 len, ub1 piece,
void **changed_bufpp, oraub8 *changed_lenp);
最初のパラメータのctxp
はコールバックのコンテキストで、OCILobRead2()
関数コールでOCIに渡されます。コールバック関数がコールされると、ctxp
で提供した情報が戻されます(OCIがINの途中でこの情報を使用することはありません)。OCILobRead2()
内のbufp
パラメータは、LOBデータが戻される格納場所へのポインタで、bufl
はこのバッファの長さを表します。これにより、指定したバッファに読み取られたデータの量がわかります。
元のOCILobRead2()
コールで提供したバッファの長さが、サーバーから戻されるデータをすべて格納するのに十分でない場合は、ユーザー定義コールバックがコールされます。この場合、piece
パラメータにより、バッファに戻された情報が最初のピース、次のピースまたは最後のピースのどれであるかが示されます。
changed_bufpp
パラメータとchanged_lenp
パラメータは、コールバック関数内で使用すると、バッファを動的に変更できます。changed_bufpp
パラメータは変更されたバッファのアドレスを指し、changed_lenp
パラメータは変更されたバッファの長さを指します。changed_bufpp
パラメータとchanged_lenp
パラメータは、アプリケーションでバッファが動的に変更されない場合、コールバック関数内で使用する必要はありません。
例9-1では、OCILobRead2()
関数を使用して、読取りコールバック関数を実装するコード・フラグメントを示しています。lobl
は前もって選択してある有効なロケータ、svchp
は有効なサービス・ハンドル、errhp
は有効なエラー・ハンドルであると想定します。この例では、すべてのLOBデータが読み取られるまで、ユーザー定義関数cbk_read_lob()
が繰り返しコールされます。
例9-1 OCILobRead2()を使用した読取りコールバック関数の実装
... 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 must 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 must be changed dynamically --*/ break; default: (void) printf("callback read error: unknown piece = %d.\n", piece); return OCI_ERROR; } return OCI_CONTINUE; }
関連項目:
9.7.4.3 コールバックを使用した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
パラメータは記憶領域へのポインタで、OCILobWrite2()
へのコールで指定されます。
コールで指定するデータをOCILobWrite2()
に挿入した後も、残りのデータがユーザー定義コールバックによって挿入されます。コールバックでは、bufp
によって示される記憶域に挿入するデータを指定し、またその長さをlenp
に指定します。さらに、piecep
パラメータを使用して、次のピース(OCI_NEXT_PIECE
)か最後のピース(OCI_LAST_PIECE
)か示します。アプリケーションで提供される記憶域ポインタにより、記憶域の割当てサイズより大きいデータが書き込まれないことを確認する必要があります。
changed_bufpp
パラメータとchanged_lenp
パラメータは、コールバック関数内で使用すると、バッファを動的に変更できます。changed_bufpp
パラメータは変更されたバッファのアドレスを指し、changed_lenp
パラメータは変更されたバッファの長さを指します。changed_bufpp
パラメータとchanged_lenp
パラメータは、アプリケーションでバッファが動的に変更されない場合、コールバック関数内で使用する必要はありません。
例9-2では、OCILobWrite2()
関数を使用して、書込みコールバック関数を実装するコード・フラグメントを示しています。lobl
は更新用にロックされている有効なロケータ、svchp
は有効なサービス・ハンドル、errhp
は有効なエラー・ハンドルであると想定しています。ユーザー定義関数cbk_write_lob()
は、アプリケーションが最後のピースを提供していることをpiecep
パラメータが示すまで繰り返しコールされます。
例9-2 OCILobWrite2()を使用した書込みコールバック関数の実装
... 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 must be changed dynamically --*/ if (this is the last data buffer) *piecep = OCI_LAST_PIECE; else *piecep = OCI_NEXT_PIECE; return OCI_CONTINUE; }
関連項目:
9.8 一時LOBのサポート
OCIでは、一時LOBの作成および解放のための関数OCILobCreateTemporary()
およびOCILobFreeTemporary()
と、LOBが一時LOBであるかどうかを判断する関数OCILobIsTemporary()
が提供されています。
一時LOBは、データベース内に永続的に格納されることはありませんが、LOBデータを操作するために、ローカル変数のように動作します。標準(永続) LOB上で動作するOCI関数は、一時LOB上でも使用できます。
永続LOBと同様に、すべての関数は一時LOBのロケータ上で動作し、実際のLOBデータにはロケータを介してアクセスされます。
一時LOBロケータは、次の型のSQL文への引数として使用できます。
-
UPDATE
- 一時LOBロケータは、NULLかどうかのテスト時にWHERE
句内の値として使用するか、あるいは関数へのパラメータとして使用できます。ロケータは、SET
句内で使用することもできます。 -
DELETE
- 一時LOBロケータは、NULLかどうかのテスト時にWHERE
句内で使用するか、あるいは関数へのパラメータとして使用できます。 -
SELECT
- 一時LOBロケータは、NULLかどうかのテスト時にWHERE
句内で使用するか、あるいは関数へのパラメータとして使用できます。また、一時LOBは、関数の戻り値を選択する場合、SELECT...INTO
文で戻される変数として使用することもできます。
ノート:
永続ロケータを一時ロケータに選択した場合、一時ロケータは永続ロケータによって上書きされます。この場合、一時LOBは暗黙的には解放されません。ユーザーはSELECT...INTO
操作の前に一時LOBを明示的に解放する必要があります。明示的に解放しなければ、一時LOBは指定したduration
の終了時まで解放されません。同じLOBを指し示している別の一時ロケータがなければ、元のロケータはSELECT...INTO
によって上書きされるため、その一時LOBを指し示すロケータはなくなります。
9.8.1 一時LOBの作成および解放
OCILobCreateTemporary()
関数を使用して一時LOBを作成します。
この関数に渡されるパラメータには、LOBの継続時間を示す値が含まれています。デフォルトの継続時間は、カレント・セッションの長さです。継続時間の終了時に、すべての一時LOBが削除されます。ユーザーは、OCILobFreeTemporary()
関数で一時LOBを明示的に解放することによって、一時LOBの領域を再生できます。一時LOBは、作成されたときは空の状態です。
一時LOBを作成するとき、その一時LOBがサーバーのバッファ・キャッシュに読み取られるかどうかも指定できます。
一時LOBを永続的にするには、OCILobCopy2()
を使用して、データを一時LOBから永続LOBにコピーします。また、一時LOBをINSERT
文のVALUES
句で使用したり、UPDATE
文内の割当てのソースとして使用したり、あるいは一時LOBを通常の永続LOB属性に割り当てて、オブジェクトをフラッシュできます。一時LOBは、標準LOBに使用する関数と同じ関数を使用して変更できます。
ノート:
空のLOBを挿入する最も効率的な方法は、値が割り当てられていない一時LOBのバインドです。これは、次のメソッドより使用するリソースが少なくてすみます。
INSERT INTO tab1 VALUES(EMPTY_CLOB())
9.8.2 一時LOBの継続時間
OCIでは、いくつかの一時LOB用の事前定義済継続時間、およびアプリケーションでアプリケーション固有の継続時間を定義するために使用できる関数のセットが用意されています。
事前定義済の継続時間とその関連属性は、次のとおりです。
-
コール(
OCI_DURATION_CALL
)、サーバー側のみ -
セッション(
OCI_DURATION_SESSION
)
セッション継続時間は、セッションまたは接続が終了した時点で期限切れになります。コール継続時間は、現行のOCIコールが終了した時点で期限切れになります。
オブジェクト・モードで実行している場合は、アプリケーション固有の継続時間も定義できます。アプリケーション固有の継続時間はユーザー期間とも呼ばれ、OCIDurationBegin()
を使用して継続開始時間を指定し、OCIDurationEnd()
を使用して継続終了時間を指定することによって定義されます。
ノート:
ユーザー定義の継続時間は、アプリケーションがオブジェクト・モードで初期化されている場合にのみ利用できます。
アプリケーション固有の継続時間にはそれぞれ、OCIDurationBegin()
で戻される継続時間識別子があり、OCIDurationEnd()
がコールされるまで一意であることが保証されます。アプリケーション固有の継続時間は、セッションの継続時間と同じに設定できます。
継続時間の終了時には、その継続時間に関連付けられたすべての一時LOBが解放されます。一時LOBに関連付けられた記述子は、OCIDescriptorFree()
コールを使用して明示的に解放する必要があります。
ユーザー継続時間はネストできるため、1つの継続時間を別のユーザー継続時間の子継続時間として定義できます。親の継続時間が子の継続時間を持ち、その子が自分の子の継続時間を持つことも可能です。
ノート:
継続時間がOCIDurationBegin()
で開始されると、パラメータの1つは親の継続時間の識別子となります。親の継続時間が終了すると、子の継続時間もすべて終了します。
9.8.3 一時LOBの解放について
OCIプログラムがSQLまたはPL/SQLからLOBロケータを取得するたびに、OCILobIsTemporary()
関数を使用して、一時ロケータかどうかをチェックします。
そうである場合は、ロケータによってアプリケーションが終了される際、OCILobFreeTemporary()
コールを使用してロケータを解放します。ロケータは、SELECTまたはOUT BIND中にDEFINEから取得できます。一時LOBの継続期間は、クライアント側に受け渡されるときに、常にセッション継続期間にアップグレードされます。アプリケーションでは、ロケータが次行のロケータで上書きされる前に次の関数を実行する必要があります。
OCILobIsTemporary(env, err, locator, is_temporary); if(is_temporary) OCILobFreeTemporary(svc, err, locator);
9.8.4 ポインタを割り当てる際の注意事項
OCILobLocator
ポインタを割り当てるときは、特に注意が必要です。
ポインタ割当てにより、LOBの簡単なコピーが作成されます。ポインタの割当て後は、ソースLOBおよびターゲットLOBはデータの同じコピーを指します。これは、割当てを実行するOCILobAssign()
またはOCILobLocatorAssign()
などのLOB APIを使用するのとは異なります。APIを使用すると、ロケータは割当て後にデータの個別のコピーを論理的に指します。
一時LOBの場合、ポインタ割当て前に、ターゲットとなるLOBロケータの一時LOBが、OCILobFreeTemporary()
によって解放されることを確認する必要があります。OCILobLocatorAssign()
を使用すると、割当てが発生する前に、ターゲットLOBロケータ変数の元の一時LOB(ある場合)が解放されます。
SQL文の実行において、OUTバインド変数を再利用する前に、OCILobFreeTemporary()
コールを使用して、既存のOUTバインドLOBロケータ・バッファ内の一時LOBを解放する必要があります。
関連項目:
-
詳細は、『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』の一時LOBパフォーマンスのガイドラインに関する項を参照してください
-
一時LOBの最適なパフォーマンスの詳細は、『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』を参照してください
9.8.5 一時LOBの例
一時LOBの使用方法を示します。
例9-3は、一時LOBをどのように使用できるかを示しています。
例9-3 一時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 that 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 (OCIStmtPrepare2(svchp, stmthp, errhp, sqlstmt, (ub4) strlen((char *)sqlstmt),
NULL, 0, (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 Log on */
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 Database */
(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 logging 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;
}
}
9.9 LOBデータ、長さおよびチャンク・サイズのプリフェッチ
小さいLOBのOCIアクセスを改善するために、LOBデータをプリフェッチしてキャッシュする間にロケータもフェッチできます。
これは内部LOB、一時LOBおよびBFILE
に適用されます。アプリケーションを準備するには、次のステップに従います。
- セッション・ハンドルの
OCI_ATTR_DEFAULT_LOBPREFETCH_SIZE
属性を設定します。この属性の値は、LOBロケータのデフォルトのプリフェッチ・データ・サイズを示します。この属性値により、セッション中にフェッチされる全LOBロケータのプリフェッチが可能になります。この属性のデフォルト値は0 (LOBデータのプリフェッチなし)です。このオプションにより、アプリケーション開発者は定義ハンドルごとにプリフェッチLOBサイズを設定する必要がなくなります。この属性を設定するか、または(ステップ3で)OCI_ATTR_LOBPREFETCH_SIZE
を設定することができます。 - 実行する文の準備ステップと定義ステップを実行します。
- 必要な場合は、定義ハンドルの
OCI_ATTR_LOBPREFETCH_SIZE
属性を設定して、フェッチするLOBロケータのデフォルト・プリフェッチ・サイズをオーバーライドできます。このオプション属性では、特定の列からフェッチされるロケータのプリフェッチ・サイズを制御できます。 OCI_ATTR_LOBPREFETCH_LENGTH
属性を、プリフェッチするLOBの長さおよびチャンク・サイズに設定します。項目1で説明した属性(OCI_ATTR_LOBPREFETCH_SIZE
)を機能させるためには、これをTRUE
に設定する必要があります。- 文を実行します。
- 個別のLOBロケータを指定してOCILobRead2()またはOCILobArrayRead()をコールします。OCIによりプリフェッチ・バッファからデータが取得され、必要な文字変換が実行され、データがLOB読取りバッファにコピーされます(LOBセマンティクスは変更されません)。要求されたデータがプリフェッチ・バッファより大きい場合は、追加のラウンドトリップが必要になります。
- OCILobGetLength2()およびOCILobGetChunkSize()をコールして、サーバーへのラウンドトリップなしで長さとチャンク・サイズを取得します。
例9-4 LOBデータ、長さおよびチャンク・サイズのプリフェッチ
... 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 4KB */ 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. 4KB 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, ...); ...
プリフェッチ・サイズは、BLOB
およびBFILE
の場合はバイト数、CLOB
の場合は文字数であることに注意してください。
例9-4では、これらのステップを説明するコード・フラグメントを示しています。
プリフェッチ・キャッシュ割当て: 記述子用のプリフェッチ・キャッシュ・バッファは、LOBロケータをフェッチするときに割り当てられます。割り当てられるバッファ・サイズは、定義ハンドルのOCI_ATTR_LOBPREFETCH_SIZE
属性によって決定され、この属性のデフォルト値は、セッション・ハンドルのOCI_ATTR_DEFAULT_LOBPREFETCH_SIZE
属性値によって示されます。キャッシュ・バッファがすでに割り当てられている場合は、必要に応じてサイズ変更します。
次の2つのLOB APIの場合、ソース・ロケータにキャッシュされたデータがあると、宛先ロケータのキャッシュが割り当てられるかサイズ変更され、キャッシュ・データがソースから宛先にコピーされます。
記述子用に割り当てられたキャッシュ・バッファ・メモリーは、記述子自体が解放されるときに解放されます。
プリフェッチ・キャッシュの無効化: 記述子用のキャッシュは、ロケータを使用してLOBデータが更新されるときに無効化されます。これは、そのキャッシュがデータの読取りに使用されなくなり、ロケータでの次のOCILobRead2()コールでラウンドトリップが発生することを意味します。
次のLOB APIにより、使用された記述子用のプリフェッチ・キャッシュが無効化されます。
-
OCILobErase() (非推奨)
-
OCILobTrim() (非推奨)
-
OCILobWrite() (非推奨)
-
OCILobWriteAppend() (非推奨)
次のLOB APIにより、宛先LOBロケータ用のキャッシュが無効化されます。
パフォーマンス・チューニング: プリフェッチ・バッファのサイズは、平均LOBサイズとクライアント側のメモリーに基づいて決定する必要があります。大量のデータがプリフェッチされる場合は、メモリーの可用性を確認する必要があります。データ・フェッチに伴うコストの方がサーバーへのラウンドトリップに伴うコストよりも大きいため、大きいLOBをプリフェッチする場合には、大幅なパフォーマンス向上は期待できない可能性があります。
このLOBプリフェッチ機能を活用できるように、LOBデータ・サイズを適正に考慮する必要があります。パラメータはアプリケーション設計の一部であるため、パラメータ値の変更が必要になれば、アプリケーションを再作成する必要があります。
アップグレード: リリース11.1より前のサーバー、リリース11.1以降のサーバーに対するリリース11.1より前のクライアントには、LOBプリフェッチを使用できません。リリース11.1より前のサーバーをリリース11.1以降のクライアントに対して使用している場合、OCIAttrSet()からエラー、または、この機能がサーバーでサポートされていないという旨のエラー・メッセージが戻されます。
9.10 SecureFiles LOBのオプション
SecureFiles (Oracle Database 11gリリース1で導入されたSTORE AS SECUREFILE
オプションを使用するLOB)の場合、CREATE
TABLE
およびALTER
TABLE
文にSQLパラメータDEDUPLICATE
を指定できます。
ノート:
非推奨のアルゴリズムには、DBMS_CRYPTO
およびネイティブ・ネットワーク暗号化の場合はMD4、MD5、DES、3DESおよびRC4関連アルゴリズム、透過的データ暗号化(TDE)の場合は3DESがあります。安全性の低い古い暗号化アルゴリズムを削除すると、これらのアルゴリズムを誤って使用することがなくなります。セキュリティ要件を満たすために、Advanced Encryption Standard (AES)などの最新の暗号化アルゴリズムを使用することをお薦めします。
この非推奨化に伴い、ネットワーク暗号化構成を確認して、非推奨になったアルゴリズムのいずれかを使用するように指定されているかどうかを確認することをお薦めします。見つかった場合は、AESなどの最新の暗号を使用するように切り替えてください。また、現在TDEデプロイメントに3DES暗号化を使用している場合は、AESなどの最新のアルゴリズムへの移行を計画する必要があります。詳細は、『Oracle Databaseセキュリティ・ガイド』を参照してください
このパラメータにより、LOB列の複数行で同一のLOBデータが同じデータ・ブロックを共有するように指定して、ディスク領域を節約できます。この機能をオフにするには、KEEP_DUPLICATES
を使用します。次の各オプションも、SECUREFILE
とともに使用されます。
パラメータCOMPRESS
では、LOB圧縮をオンにします。NOCOMPRESS
では、LOB圧縮をオフにします。
パラメータENCRYPT
では、LOB暗号化をオンにして、オプションで暗号化アルゴリズムを選択します。NOENCRYPT
では、LOB暗号化をオフにします。各LOB列には、他のLOB列または非LOB列の暗号化に関係なく、独自の暗号化仕様を設定できます。有効なアルゴリズムは、3DES168
、AES128
、AES192
およびAES256
です。
リリース11.1より前に使用されていたパラタイムがデフォルトです。このデフォルトのLOBパラダイムは、オプションSTORE AS BASICFILE
でも明示的に設定されます。
次のOCI関数が、SECUREFILE
機能で使用されます。
-
OCILobGetOptions()
-
OCILobSetOptions()
-
OCILobGetContentType()
-
OCILobSetContentType()
関連項目:
-
関連SQL関数およびPL/SQLパッケージの相互参照の詳細と、SecureFilesへの移行については、『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』を参照してください