9.4 LOB用のOCI API

Oracle Call Interface (OCI) LOB関数を使用すると、CでLOBにアクセスして変更できます。

OCIでのLOBデータのプリフェッチ

OCIクライアントを使用する場合、フェッチ中にLOBロケータと一緒にデータおよびメタデータ(長さおよびチャンク・サイズ)の一部をプリフェッチすると、サーバー・ラウンドトリップ数を削減できます。これは、永続LOB、一時LOBおよびBFILEに適用されます。サイズが小さいLOBから中程度のLOBの場合、ほとんどのLOBがプリフェッチ・サイズより小さくなるようにプリフェッチ長を設定することをお薦めします。

LOBプリフェッチ・サイズはセッション・レベルで設定でき、文レベルまたは列レベルで上書きできます。

OCIAttrSet()関数を使用して、セッションのプリフェッチ・サイズを設定します。デフォルトのセッション・プリフェッチ・サイズは0です。
default_lobprefetch_size = 32000;
OCIAttrSet(authp, OCI_HTYPE_SESSION, &default_lobprefetch_size , 0,
      OCI_ATTR_DEFAULT_LOBPREFETCH_SIZE, errhp));

セッション・レベルのデフォルトのプリフェッチ・サイズは、列レベルで上書きできます。このためには、最初に列レベル属性OCI_ATTR_LOBPREFETCH_LENGTHTRUEに設定し、次に定義ハンドルの列レベルのプリフェッチ・サイズ属性OCI_ATTR_LOBPREFETCH_SIZEを設定して、セッション・レベルのデフォルトのLOBプリフェッチ・サイズをオーバーライドする必要があります。次のコード・スニペットは、セッション・レベルでプリフェッチ・サイズを設定する方法を示しています。

prefetch_length = TRUE;
status = OCIAttrSet(defhp, OCI_HTYPE_DEFINE, &prefetch_length, 0, OCI_ATTR_LOBPREFETCH_LENGTH, errhp);
 
lpf_size = 32000;
OCIAttrSet(defhp, OCI_HTYPE_DEFINE, &lpf_size, sizeof(ub4), OCI_ATTR_LOBPREFETCH_SIZE, errhp);
次のコード・スニペットを使用して、定義のプリフェッチ・サイズを取得できます。
ub4 get_lpf_size = 0;
OCIAttrGet(defhp, OCI_HTYPE_DEFINE,&get_lpf_size, 0,OCI_ATTR_LOBPREFETCH_SIZE, errhp);

OCIにおける固定幅文字セットと可変幅文字セットの規則

OCIの場合、固定幅のクライアント側文字セットには、次の規則が適用されます。

  • CLOBおよびNCLOB: offsetおよびamountパラメータは、常に文字で表されます。

  • BLOBおよびBFILE: offsetおよびamountパラメータは、常にバイトで表されます。

次の規則は、可変幅のクライアント側文字セットに対してのみ適用されます。

  • オフセット・パラメータ:

    クライアント側文字セットが可変幅かどうかにかかわらず、オフセット・パラメータは常に次のように表されます。

    • CLOBおよびNCLOB: 文字で表されます。

    • BLOBおよびBFILE: バイトで表されます。

  • 量パラメータ:

    量パラメータは、常に次のように表されます。

    • サーバー側LOBを参照する場合: 文字で表されます。

    • クライアント側バッファを参照する場合: バイトで表されます。

  • OCILobGetLength2():

    クライアント側文字セットが可変幅かどうかにかかわらず、出力の長さは次のように表されます。

    • CLOBおよびNCLOB: 文字で表されます。

    • BLOBおよびBFILE: バイトで表されます。

  • OCILobRead2():

    可変幅のクライアント側文字セット、CLOBおよびNCLOBでは次のようになります。

    • 入力量は、文字で表されます。入力量は、サーバー側のCLOBまたはNCLOBから読み取られる文字数を表します。

    • 出力量は、バイトで表されます。出力量は、バッファbufpに読み取られたバイト数を表します。

  • OCILobWrite2(): 可変幅のクライアント側文字セット、CLOBおよびNCLOBでは次のようになります。

    • 入力量は、バイトで表されます。入力量は、入力バッファbufpにあるデータのバイト数を表します。

    • 出力量は、文字で表されます。出力量は、サーバー側のCLOBまたはNCLOBに書き込まれた文字数を表します。

  • OCILob操作の量操作: OCILobCopy2()OCILobErase2()OCILobLoadFromFile2()およびOCILobTrim2()などの操作の場合、amountパラメータは、すべての操作がサーバー上のLOBデータの量を参照するため、クライアント側の文字セットにかかわらずCLOBおよびNCLOBの文字数です。

量パラメータ

OCILobRead2()およびOCILobWrite2()関数を使用する場合、LOB全体の読取りまたは書込みを行うには、次のように入力amountパラメータを設定します。

表9-4 LOB全体の読取り/書込みを行うための特殊量パラメータ設定

  OCILobRead2 OCILobWrite2
piece = OCI_ONE_PIECE LOB全体を読み取るには、amountをUB8MAXVALに設定します。  
ポーリングによるストリーミング ループ内のデータ全体を読み取るには、amountを0に設定します amountを0に設定すると、OCI_LAST_PIECEまでバッファ・サイズの書込みが続行されます。
コールバックによるストリーミング データ全体が読み取られるまでコールバックがコールされるように、量0を設定します。 コールバックによってOCI_LAST_PIECEが返されるまでコールバックがコールされるように、amountを0に設定します。

表9-5 OCILobLocatorのOCI属性

ATTRIBUTE OCIAttrSet OCIAttrGet
OCI_ATTR_LOBEMPTY ディスクリプタを空のLOBに設定します。 該当なし
OCI_ATTR_LOB_REMOTE 該当なし LOBロケータがリモート・データベースからの場合はTRUE、それ以外の場合はFALSEに設定されます。
OCI_ATTR_LOB_TYPE 該当なし LOB型(CLOB / BLOB / BFILE)を保持します。
OCI_ATTR_LOB_IS_VALUE 該当なし 値LOBからの場合はTRUE、それ以外の場合はFALSEに設定されます。
OCI_ATTR_LOB_IS_READONLY 該当なし 読取り専用LOBの場合はTRUE、それ以外の場合はFALSEに設定されます。
OCI_ATTR_LOBPREFETCH_LENGTH TRUEに設定すると、属性はプリフェッチを有効にし、LOBロケータの選択操作の実行中にLOBの長さおよびチャンク・サイズをプリフェッチします。 ロケータのプリフェッチが有効になっている場合は、TRUEに設定します。
OCI_ATTR_LOBPREFETCH_SIZE LOBのデフォルトのプリフェッチ・サイズをオーバーライドします。OCI_ATTR_LOBPREFETCH_LENGTH属性をTRUEに設定するための前提条件があります。 ロケータのプリフェッチ・サイズを返します。

表9-6 LOB用のOCI関数

分類 関数およびプロシージャ 説明
健全性チェック OCILobLocatorIsInit() LOBロケータが初期化されているかどうかを確認します。
オープンとクローズ OCILobOpen() LOBをオープン
OCILobIsOpen() LOBがオープンしているかどうかの確認
OCILobClose() LOBのクローズ
読取り操作 OCILobGetLength2() LOB長の取得
OCILobGetStorageLimit() データベース構成のLOB記憶域制限を取得します
OCILobGetChunkSize() 最適な読取りまたは書込みサイズの取得
OCILobRead2() 指定されたオフセットからLOBのデータを読み取ります
OCILobArrayRead() 1回のラウンドトリップで複数のロケータを使用してデータを読み取ります。
OCILobCharSetId() LOBの文字セットIDを戻します。
OCILobCharSetForm() LOBの文字セット・フォームを戻します。
変更操作 OCILobWrite2() 指定されたオフセットからLOBにデータを書き込みます
OCILobArrayWrite() 1回のラウンドトリップで複数のロケータを使用してデータを書き込みます。
OCILobWriteAppend2() データをLOBの終わりに書き込みます。
OCILobErase2() 指定のオフセットから開始して、LOBの一部を消去します
OCILobTrim2() LOB値の指定された長さまでの切捨て
複数のロケータを含む操作 OCILobIsEqual() 2つのLOBロケータが同じLOBを参照しているかどうかを確認します。
OCILobAppend() LOB値を別のLOBに追加します
OCILobCopy2() LOBの全体または一部を他のLOBにコピーします。
OCILobLocatorAssign() LOBを別のLOBに割り当てます
OCILobLoadFromFile2() BFILEデータのLOBへのロード
SecureFilesに固有の操作 OCILObGetOptions() SecureFilesのオプション(重複除外、圧縮、暗号化)を戻します。
OCILObSetOptions() SecureFilesのLOB機能(重複除外および圧縮)を設定します
OCILobGetContentType() SecureFilesのコンテンツ文字列を取得します
OCILobSetContentType() SecureFilesにコンテンツ文字列を設定します

例9-4 LOB用のOCI API

/* Define SQL statements to be used in program. */
#define LOB_NUM_QUERIES 2
 
static text *selstmt[LOB_NUM_QUERIES] = {
    (text *) "select ad_sourcetext from print_media where product_id = 1", /* 0 */
    (text *) "select ad_sourcetext from print_media where product_id = 2 for update",
};
 
sword run_query(ub4 index, ub2 dty)
{ 
  OCILobLocator *c1 = (OCILobLocator *)0;
  OCILobLocator *c2 = (OCILobLocator *)0;
 
  OCIStmt       *stmthp;
  OCIDefine     *defn1p = (OCIDefine *) 0;
  OCIDefine     *defn2p = (OCIDefine *) 0;
  OCIBind       *bndp1  = (OCIBind *)   0;
  OCIBind       *bndp2  = (OCIBind *)   0;
 
  ub8            loblen;
  ub1            lbuf[128];
  ub1            inbuf[9] = "modified";
  ub1            inbuf_len = 8;
  ub8            amt = 15;
  ub8            bamt = 0;
  ub4            csize = 0;
  ub8            slimit = 0;
  boolean        flag = FALSE;
  boolean        boolval = TRUE;
  ub4            id = 10;
 
 
  CHECK_ERROR (OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp,
                              OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0));
 
  /************** Allocate descriptors ***********************/
  CHECK_ERROR (OCIDescriptorAlloc((dvoid *) envhp, (dvoid **) &c1,
                                  (ub4)OCI_DTYPE_FILE, (size_t) 0,
                                  (dvoid **) 0));
 
  CHECK_ERROR (OCIDescriptorAlloc((dvoid *) envhp, (dvoid **) &c2,
                                 (ub4)OCI_DTYPE_FILE, (size_t) 0,
 
  /********** Execute selstmt[0] to get c1  ***********************/
  CHECK_ERROR (OCIStmtPrepare(stmthp, errhp, selstmt[0],
                              (ub4) strlen((char *) selstmt[0]),
                              (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT));
 
  CHECK_ERROR (OCIDefineByPos(stmthp, &defn1p, errhp, (ub4) 1, (dvoid *) &c1,
                              (sb4) -1, SQLT_CLOB, (dvoid *) 0, (ub2 *) 0,
                              (ub2 *)0, (ub4) OCI_DEFAULT));
 
  CHECK_ERROR (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
                              (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL,
                              OCI_DEFAULT));
 
  /********** Execute selstmt[1] to get c2 **********************/
  CHECK_ERROR (OCIStmtPrepare(stmthp, errhp, selstmt[1],
                              (ub4) strlen((char *) selstmt[1]),
                              (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT));
 
  CHECK_ERROR (OCIDefineByPos(stmthp, &defn1p, errhp, (ub4) 1, (dvoid *) &c2,
                              (sb4) -1, SQLT_CLOB, (dvoid *) 0, (ub2 *) 0,
                              (ub2 *)0, (ub4) OCI_DEFAULT));
 
  CHECK_ERROR (OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
                              (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL,
                              OCI_DEFAULT));
 
   
  /*------------------------------------------------------------------*/
  /*---------------------- Sanity Checking ---------------------------*/
  /*------------------------------------------------------------------*/
 
  CHECK_ERROR (OCILobLocatorIsInit(envhp, errhp, (OCILobLocator *) c1,
                                   &boolval));
  if (boolval)
    printf("LOB locator is initialized! \n");
  else
    printf("LOB locator is NOT initialized \n");
 
 
  /*------------------------------------------------------------------*/
  /*----------------------- Open/Close -------------------------------*/
  /*------------------------------------------------------------------*/
 
  /*----------------------- Opening a CLOB ---------------------------*/
  CHECK_ERROR (OCILobOpen(svchp, errhp, c1, (ub1)OCI_LOB_READONLY));
  printf("OCILobOpen: Works\n");
  /*-------------- Determining Whether a CLOB Is Open ---------------*/
  CHECK_ERROR (OCILobIsOpen(svchp, errhp, c1,  &boolval));
  printf("OCILobIsOpen: %s\n", (boolval)?"TRUE":"FALSE");
 
  /*----------------------- Closing a LOB ---------------------------*/
  CHECK_ERROR (OCILobClose(svchp, errhp, c1));
  printf("OCILobClose: Works\n");
 
  /*------------------------------------------------------------------*/
  /*-------------------- LOB Read Operations -------------------------*/
  /*------------------------------------------------------------------*/
 
  printf("OCILobFileOpen: Works\n");
 
  /*----------------- Getting the Length of a LOB --------------------*/
  CHECK_ERROR (OCILobGetLength2(svchp, errhp, c1, &loblen));
  printf("OCILobGetLength2: loblen: %d \n", loblen);
 
  /*----------------- Getting the Storage Limit of a LOB -------------*/
  CHECK_ERROR (OCILobGetStorageLimit(svchp, errhp, c1, &slimit));
  printf("OCILobGetStorageLimit: storage limit: %ld \n", slimit);
 
 /*----------------- Getting the Chunk Size of a LOB -----------------*/
  CHECK_ERROR (OCILobGetChunkSize(svchp, errhp, c1, &csize));
  printf("OCILobGetChunkSize: storage limit: %d \n", csize);
 
  /*------------------------ Reading LOB Data ------------------------*/
  CHECK_ERROR (OCILobRead2(svchp, errhp, c1, &amt,
                           NULL, (oraub8)1, lbuf,
                           (oraub8)sizeof(lbuf), OCI_ONE_PIECE ,(dvoid*)0,
                           NULL, (ub2)0, (ub1)SQLCS_IMPLICIT));
  printf("OCILobRead2: buf: %.*s amt: %lu\n", amt, lbuf, amt);
 
  /*------------------------------------------------------------------*/
  /*-------------------- Modifying a LOB -----------------------------*/
  /*------------------------------------------------------------------*/
 
  /*---------------------- Writing Data to LOB -----------------------*/
  amt = 8;
  CHECK_ERROR (OCILobWrite2(svchp, errhp, c2, &bamt, &amt, 1,
                (dvoid *) inbuf, (ub8)inbuf_len, OCI_ONE_PIECE, (dvoid *)0,
                (OCICallbackLobWrite2)0,
                (ub2) 0, (ub1) SQLCS_IMPLICIT));
 
  /*---------------------- Write Append to a LOB ---------------------*/
  /* Append 8 characters */
  amt = 8;
  CHECK_ERROR (OCILobWriteAppend2(svchp, errhp, c2, &bamt, &amt,
                (dvoid *) inbuf, (ub8)inbuf_len, OCI_ONE_PIECE, (dvoid *)0,
                (OCICallbackLobWrite2)0,
                (ub2) 0, (ub1) SQLCS_IMPLICIT));
 
  /*---------------------- Erase part of LOB contents ----------------*/
  /* Erase 5 characters */
  amt = 5;
  CHECK_ERROR (OCILobErase2(svchp, errhp, c2, &amt, 2));
 
  /*------------------------- Trim a LOB -----------------------------*/
  amt = 1000;
  CHECK_ERROR (OCILobTrim2(svchp, errhp, c2, amt));
  printf("OCILobTrim2  Works! \n");
 
  /*------------------------------------------------------------------*/
  /*------------- Operations involving 2 locators --------------------*/
  /*------------------------------------------------------------------*/
 
  /*--------------- Check Equality of LOB locators -------------------*/
  CHECK_ERROR ( OCILobIsEqual(envhp, c1, c2, &boolval))
  printf("OCILobIsEqual %s\n", (boolval)?"TRUE":"FALSE");
 
  /*--------------- Append contents of a LOB to another LOB ----------*/
  CHECK_ERROR(OCILobAppend(svchp, errhp, c2, c1));
  printf("OCILobAppend: Works! \n");
 
  /*------------------------ LOB Copy --------------------------------*/
  /* Copy 10 characters from offset 1 of source to offset 2 of destination*/
  CHECK_ERROR (OCILobCopy2(svchp, errhp, c2, c1, 10, 2, 1));
  printf("OCILobCopy2: Works! \n");
 
 /*------------------- LOB Locator Assign ---------------------------*/
  CHECK_ERROR (OCILobLocatorAssign(svchp, errhp, c1, &c2));
  printf("OCILobLocatorAssign: Works! \n");
 
  /* Free the LOB descriptors which were allocated */
  OCIDescriptorFree((dvoid *) c1, (ub4) SQLT_CLOB);
  OCIDescriptorFree((dvoid *) c2, (ub4) SQLT_CLOB);
 
  CHECK_ERROR (OCIHandleFree((dvoid *) stmthp, OCI_HTYPE_STMT));
}

9.4.1 OCIにおけるLOBデータの効率的な読取り

この項では、LOBの内容をバッファに読み取る方法について説明します。

OCIでのストリーム読取り

大量のLOBデータを最も効率よく読み取るには、ポーリングまたはコールバックによってストリーム・メカニズムを有効にしたOCILobRead2()を使用します。そのためには、次のようにoffsetパラメータを使用して読取り開始位置を指定します。

ub8  char_amt =  0;
ub8  byte_amt =  0;
ub4  offset = 1000;

OCILobRead2(svchp, errhp, locp, &byte_amt, &char_amt, offset, bufp, bufl,
            OCI_ONE_PIECE, 0, 0, 0, 0);

ポーリング・モードを使用すると、バッファがいっぱいにならない場合があるため、各OCILobRead2()コール後にbyte_amtパラメータの値を調べて、バッファに何バイト読み取られたかを確認してください。

コールバックを使用する場合、lenpパラメータはコールバックへの入力で、バッファ内で格納されたバイト数を示します。バッファの空き領域を確認するため、コールバック処理中にlenpパラメータを必ずチェックしてください。

LOB配列読取り

この項では、OCILobArrayRead()を使用して、1回のラウンドトリップで複数のロケータに対してLOBデータを読み取る方法について説明します。

OCIアプリケーションの例では、プログラムに次のようなSQL文が用意されているものとします。

SELECT lob1 FROM lob_table;

lob1はLOB列であり、lob_arrayはLOB列に対応する定義変数の配列です。

OCILobLocator * lob_array[10];

...
 for (i=0; i<10, i++)        /* initialize array of locators */
    lob_array[i] = OCIDescriptorAlloc(..., OCI_DTYPE_LOB, ...);
 
...
 
OCIDefineByPos(..., 1, (dvoid *) lob_array, ... SQLT_CLOB, ...);
 
/* Execute the statement with iters = 10 to do an array fetch of 10 locators. */
OCIStmtExecute ( <service context>, <statement handle>, <error handle>,
                 10,    /* iters  */ 
                 0,     /* row offset */
                 NULL,  /* snapshot IN */
                 NULL,  /* snapshot out */
                 OCI_DEFAULT /* mode */);
...
 
  ub4 array_iter = 10;
  char  *bufp[10];
  oraub8 bufl[10];
  oraub8 char_amtp[10];
  oraub8 offset[10];  
 
 for (i=0; i<10; i++)
  {
    bufp[i] = (char *)malloc(1000);
    bufl[i] = 1000;
    offset[i] = 1;
    char_amtp[i] = 1000;  /* Single byte fixed width char set. */
  } 
 
/* Read the 1st 1000 characters for all 10 locators in one
 * round trip. Note that offset and amount need not be 
 * same for all the locators. */
 
OCILobArrayRead(<service context>, <error handle>,
                &array_iter, /* array size */
                lob_array,   /* array of locators */
                NULL,        /* array of byte amounts */
                char_amtp,   /* array of char amounts */
                offset,      /* array of offsets */
       (void **)bufp,        /* array of read buffers */
                bufl,        /* array of buffer lengths */
                OCI_ONE_PIECE,  /* piece information */
                NULL,           /* callback context */
                NULL,           /* callback function */
                0,              /* character set ID - default */
                SQLCS_IMPLICIT);/* character set form */
 
 ...
 
for (i=0; i<10; i++)
  {
    /* Fill bufp[i] buffers with data to be written */
    strncpy (bufp[i], "Test Data------", 15);
    bufl[i] = 1000;
    offset[i] = 50;
    char_amtp[i] = 15;  /* Single byte fixed width char set. */
  } 
 
/* Write the 15 characters from offset 50 to all 10 
 * locators in one round trip. Note that offset and
 * amount need not be same for all the locators. */
 */
 
OCILobArrayWrite(<service context>, <error handle>,
                  &array_iter, /* array size */
                  lob_array,   /* array of locators */
                  NULL,        /* array of byte amounts */
                  char_amtp,   /* array of char amounts */
                  offset,      /* array of offsets */
             (void **)bufp,    /* array of read buffers */
                  bufl,        /* array of buffer lengths */
                  OCI_ONE_PIECE,  /* piece information */
                  NULL,           /* callback context */
                  NULL,           /* callback function */
                  0,              /* character set ID - default */
                  SQLCS_IMPLICIT);/* character set form */
...

ストリームによるLOB配列読取り

LOB配列APIは、複数ピースでのLOBデータの読取り/書込みに使用できます。これには、ポーリング手法やコールバック・ファンクションを使用します。これにより、ロケータの配列について複数ピースで順に読取り/書込みが実行されます。ポーリングの場合、各ピースの読取り/書込みの後、array_iterパラメータ(OUT)でそのデータ読取り/書込み時のロケータの索引が示されると、APIがアプリケーションに戻ります。コールバックの場合、array_iterをINパラメータとして各ピースの読取り/書込みを実行すると、ファンクションがコールされます。

次の点に注意してください。

  • いくつかのロケータについては1つのピースでデータを読取り/書込みし、その他のロケータについては複数ピースでデータを読取り/書込みすることが可能です。読取り/書込み対象データの全体が収まるだけの十分なバッファ長を持つロケータについては、データは1つのピースで読取り/書込みされます。

  • アプリケーションでは、ロケータごとに異なる量の値およびバッファ長を使用できます。

  • アプリケーションでは、1つ以上のロケータに対して量の値としてゼロを渡し、これらのロケータに対して純粋なストリーミングを指定できます。読取りの場合、LOBデータはこれらのロケータに対して最後まで読み取られます。書込みの場合、これらのロケータに対してOCI_LAST_PIECEが指定されるまでデータが書き込まれます。

コールバックによるLOB配列読取り

次の例では、バッファ・サイズが1KBの10個のロケータのそれぞれに対して、10KBのデータが読み取られます。各ロケータには、すべてのデータを読み取るために10ピースが必要です。コールバック関数またはファンクションは100(10 × 10)回コールされ、ピースが順次戻されます。

/* Fetch the locators */ 
...
     ub4    array_iter = 10;
     char  *bufp[10];
     oraub8 bufl[10];
     oraub8 char_amtp[10];
     oraub8 offset[10];
     sword  st;  

     for (i=0; i<10; i++)
     {
       bufp[i] = (char *)malloc(1000);
       bufl[i] = 1000;
       offset[i] = 1;
       char_amtp[i] = 10000;       /* Single byte fixed width char set. */
      }

      st =  OCILobArrayRead(<service context>, <error handle>,
                        &array_iter, /* array size */
                        lob_array,   /* array of locators */
                        NULL,        /* array of byte amounts */
                        char_amtp,   /* array of char amounts */
                        offset,      /* array of offsets */
               (void **)bufp,        /* array of read buffers */
                        bufl,        /* array of buffer lengths */
                        OCI_FIRST_PIECE,  /* piece information */
                        ctx,              /* callback context */
                        cbk_read_lob,     /* callback function */
                        0,                /* character set ID - default */
                        SQLCS_IMPLICIT);
...
/* Callback function for LOB array read. */
sb4 cbk_read_lob(dvoid *ctxp, ub4 array_iter, CONST dvoid *bufxp, oraub8 len,
                 ub1 piece, dvoid **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(last piece) for %dth locator \n\n",
                piece_count, array_iter ); 
      piece_count = 0; 
      break; 
    case OCI_FIRST_PIECE: 
      /*--- buffer processing code goes here ---*/ 
      (void) printf("callback read the 1st piece for %dth locator\n",
                    array_iter); 
      /* --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 for %dth locator\n",
                    piece_count, array_iter); 
      /* --Optional code to set changed_bufpp and changed_lenp if the  buffer
           must be changed dynamically --*/ 
      break; 
      default:
      (void) printf("callback read error: unkown piece = %d.\n", piece); 
      return OCI_ERROR; 
   } 
    return OCI_CONTINUE;
}
...

ポーリング・モードでのLOB配列読取り

次の例では、バッファ・サイズが1KBの10個のロケータのそれぞれに対して、10KBのデータが読み取られます。完全なデータを読み取るには、ロケータごとに10ピースが必要です。すべてのデータをフェッチするには、OCILobArrayRead()を100 (10*10)回コールする必要があります。まず、OCI_FIRST_PIECEpieceパラメータとしてOCILobArrayRead()をコールします。このコールで、最初のロケータに対して最初の1Kピースが戻されます。次に、アプリケーションでロケータに対するすべてのピースの読取りが終了し、OCI_SUCCESSが戻されるまでOCILobArrayRead()がループでコールされ、ます。この例では、99回ループしてロケータのピースを順次戻しています。

/* Fetch the locators */ 
...
 
     /* array_iter parameter indicates the number of locators in the array read.
      * It is an IN parameter for the 1st call in polling and is ignored as IN
      * parameter for subsequent calls. As OUT parameter it indicates the locator
      * index for which the piece is read.
      */
 
     ub4    array_iter = 10;
     char  *bufp[10];
     oraub8 bufl[10];
     oraub8 char_amtp[10];
     oraub8 offset[10];
     sword  st;  
 
     for (i=0; i<10; i++)
     {
       bufp[i] = (char *)malloc(1000);
       bufl[i] = 1000;
       offset[i] = 1;
       char_amtp[i] = 10000;       /* Single byte fixed width char set. */
     } 
 
     st =  OCILobArrayRead(<service context>, <error handle>,
                         &array_iter, /* array size */
                         lob_array, /* array of locators */
                         NULL,      /* array of byte amounts */
                         char_amtp, /* array of char amounts */
                         offset,    /* array of offsets */
                (void **)bufp,      /* array of read buffers */
                         bufl,      /* array of buffer lengths */
                         OCI_FIRST_PIECE, /* piece information */
                         NULL,           /* callback context */
                         NULL,           /* callback function */
                         0,              /* character set ID - default */
                         SQLCS_IMPLICIT); /* character set form */
 
     /* First piece for the first locator is read here. 
      * bufp[0]          => Buffer pointer into which data is read.
      * char_amtp[0 ]    => Number of characters read in current buffer
      *
      */ 
 
     While ( st == OCI_NEED_DATA)
     {  
          st =  OCILobArrayRead(<service context>, <error handle>,
                          &array_iter, /* array size */
                          lob_array, /* array of locators */
                          NULL,      /* array of byte amounts */
                          char_amtp, /* array of char amounts */
                          offset,    /* array of offsets */
                 (void **)bufp,      /* array of read buffers */
                          bufl,      /* array of buffer lengths */
                          OCI_NEXT_PIECE, /* piece information */
                          NULL,           /* callback context */
                          NULL,           /* callback function */
                          0,              /* character set ID - default */
                          SQLCS_IMPLICIT);
 
       /* array_iter returns the index of the current array element for which 
        * data is read. for example, aray_iter = 1 implies first locator,
        * array_iter = 2 implies second locator and so on.
        *
        * lob_array[ array_iter - 1]=> Lob locator for which data is read. 
        * bufp[array_iter - 1]      => Buffer pointer into which data is read.
        * char_amtp[array_iter - 1] => Number of characters read in current buffer
        */
 
...
        /* Consume the data here */
...
     }

9.4.2 OCIにおけるLOBデータの効率的な書込み

この項では、バッファの内容をLOBに書き込む方法について説明します。

OCIにおけるストリーム書込み

大量のLOBデータを最も効率よく書き込むには、ポーリングまたはコールバックを使用してストリーム・メカニズムを有効にしたOCILobWrite2()を使用します。LOBに書き込むデータの量がわかっている場合は、OCILobWrite2()のコール時にそのデータ量を指定します。これにより、ディスク上のLOBデータが確実に連続したものになります。領域を効率的に利用できるのみでなく、LOBデータの連続性により、その後の操作で読み書きの速度が速くなります。

コールバックによるLOB配列書込み

次の例では、バッファ・サイズが1KBの10個のロケータのそれぞれに対して、10KBのデータが書き込まれます。合計100ピース(ロケータごとに10ピース)を書き込む必要があります。最初のピースはOCILobArrayWrite()コールによって提供されます。コールバック関数またはファンクションは99回コールされ、書込み対象の以降のピースに対してデータが取得されます。

/* Fetch the locators */
...

    ub4    array_iter = 10;
    char  *bufp[10];
    oraub8 bufl[10];
    oraub8 char_amtp[10];
    oraub8 offset[10];
    sword  st; 
 
    for (i=0; i<10; i++)
    {
      bufp[i] = (char *)malloc(1000);
      bufl[i] = 1000;
      offset[i] = 1;
      char_amtp[i] = 10000;       /* Single byte fixed width char set. */
    }
 
 st =  OCILobArrayWrite(<service context>, <error handle>,
                        &array_iter, /* array size */
                        lob_array,   /* array of locators */
                        NULL,        /* array of byte amounts */
                        char_amtp,   /* array of char amounts */
                        offset,      /* array of offsets */
               (void **)bufp,        /* array of write buffers */
                        bufl,        /* array of buffer lengths */
                        OCI_FIRST_PIECE,  /* piece information */
                        ctx,              /* callback context */
                        cbk_write_lob     /* callback function */
                        0,                /* character set ID - default */
                        SQLCS_IMPLICIT);

...

/* Callback function for LOB array write. */
sb4 cbk_write_lob(dvoid *ctxp, ub4 array_iter, dvoid *bufxp, oraub8 *lenp,
                  ub1 *piecep, ub1 *changed_bufpp, oraub8 *changed_lenp)
{
 static ub4 piece_count = 0;
 piece_count++; 

 printf (" %dth piece written  for %dth locator \n\n", piece_count, array_iter);

 /*-- 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 for current locator)
     *piecep = OCI_LAST_PIECE;     
  else if (this is the first data buffer for the next locator)
     *piecep = OCI_FIRST_PIECE;
     piece_count = 0;
  else
     *piecep = OCI_NEXT_PIECE;
 
     return OCI_CONTINUE;
    }
...

ポーリング・モードでのLOB配列書込み

次の例では、バッファ・サイズが1KBの10個のロケータのそれぞれに対して、10KBのデータが書き込まれます。OCILobArrayWrite()は、すべてのデータを書き込むために100(10 × 10)回コールされる必要があります。このファンクションは、OCILobWrite2()と同様の方法で使用されます。

/* Fetch the locators */
...
 
/* array_iter parameter indicates the number of locators in the array read.
 * It is an IN parameter for the 1st call in polling and is ignored as IN
 * parameter for subsequent calls. As an OUT parameter it indicates the locator
 * index for which the piece is written.
 */
 
ub4    array_iter = 10;
char  *bufp[10];
oraub8 bufl[10];
oraub8 char_amtp[10];
oraub8 offset[10];
sword  st;
int    i, j; 
 
for (i=0; i<10; i++)
{
  bufp[i] = (char *)malloc(1000);
  bufl[i] = 1000;
  /* Fill bufp here. */
...
  offset[i] = 1;
  char_amtp[i] = 10000;       /* Single byte fixed width char set. */  
}
 
for (i  = 1; i <= 10; i++)
{
 /* Fill up bufp[i-1] here.  The first piece for ith locator would be written from
    bufp[i-1] */
...
    st =  OCILobArrayWrite(<service context>, <error handle>,
                      &array_iter, /* array size */
                      lob_array,   /* array of locators */
                      NULL,        /* array of byte amounts */
                      char_amtp,   /* array of char amounts */
                      offset,      /* array of offsets */
             (void **)bufp,        /* array of write buffers */
                      bufl,        /* array of buffer lengths */
                      OCI_FIRST_PIECE, /* piece information */
                      NULL,            /* callback context */
                      NULL,            /* callback function */
                      0,               /* character set ID - default */
                      SQLCS_IMPLICIT); /* character set form */
 
 for ( j = 2; j < 10; j++) 
 {
 /* Fill up bufp[i-1] here.  The jth piece for ith locator would be written from
    bufp[i-1] */
...
 st =  OCILobArrayWrite(<service context>, <error handle>,
                        &array_iter, /* array size */
                        lob_array,   /* array of locators */
                        NULL,        /* array of byte amounts */
                        char_amtp,   /* array of char amounts */
                        offset,      /* array of offsets */
               (void **)bufp,        /* array of write buffers */
                        bufl,        /* array of buffer lengths */
                        OCI_NEXT_PIECE, /* piece information */
                        NULL,           /* callback context */
                        NULL,           /* callback function */
                        0,              /* character set ID - default */
                        SQLCS_IMPLICIT);
 
    /* array_iter returns the index of the current array element for which
     * data is being written. for example, aray_iter = 1 implies first locator,
     * array_iter = 2 implies second locator and so on. Here i = array_iter.
     *
     * lob_array[ array_iter - 1] => Lob locator for which data is written.
     * bufp[array_iter - 1]       => Buffer pointer from which data is written.
     * char_amtp[ array_iter - 1] => Number of characters written in
     * the piece just written
     */
}

/* Fill up bufp[i-1] here.  The last piece for ith locator would be written from
   bufp[i -1] */
...       
 st =  OCILobArrayWrite(<service context>, <error handle>,
                        &array_iter, /* array size */
                        lob_array,   /* array of locators */
                        NULL,        /* array of byte amounts */
                        char_amtp,   /* array of char amounts */
                        offset,      /* array of offsets */
               (void **)bufp,        /* array of write buffers */
                        bufl,        /* array of buffer lengths */
                        OCI_LAST_PIECE,  /* piece information */
                        NULL,            /* callback context */
                        NULL,            /* callback function */
                        0,               /* character set ID - default */
                        SQLCS_IMPLICIT);
}

...