8.4 OCIにおけるLOB用のデータ・インタフェース
この項では、LOB用のデータ・インタフェースに組み込まれているOCI関数について説明します。これらのOCI関数は、VARCHAR
データ型の場合とまったく同じようにLOBデータ型に対して機能します。
これらの関数を使用すると、LOBに対してOCIでINSERT
、UPDATE
およびフェッチ操作を実行できます。これらの手法は、文字データまたはバイナリ・データを格納するために他のデータ型で使用する手法と同じです。
ノート:
配列のバインドおよび定義インタフェースを使用すると、LOBを含む複数の行を1回のラウンドトリップで挿入および選択できます。- OCIにおけるLOBのバインド
この項では、OCIでLOBデータ型をバインドするために使用できる操作について説明します。 - OCIにおけるLOBの定義
この項で説明するOCI関数は、LOB型をデータ型および出力バッファに関連付けます。 - LOB用データ・インタフェースでのOCIのマルチバイト文字セットの併用
この項では、OCIクライアントでマルチバイト文字セットを使用する場合のLOB用データ・インタフェースの機能について説明します。 - LOB長の取得
この項では、OCIアプリケーションでLOBの長さをフェッチする方法について説明します。 - OCI関数を使用したLOB列のINSERTまたはUPDATEの実行
この項では、データ・インタフェースを使用してLOB列またはLOB属性に対してINSERT
またはUPDATE
操作を実行する様々な方法について説明します。 - OCIデータ・インタフェースを使用したLOBデータのフェッチ
この項では、データ・インタフェースを使用してOCIの永続LOBまたは一時LOBからデータをフェッチする方法について説明します。 - OCIからのPL/SQLおよびCバインド
この項では、LOBに関するOCIからのPL/SQLおよびCバインドについて説明します。
親トピック: LOBのデータ・インタフェース
8.4.1 OCIにおけるLOBのバインド
この項では、OCIでLOBデータ型をバインドするために使用できる操作について説明します。
-
INSERT
操作およびUPDATE
操作に対する標準、ピース単位およびコールバックのバインド -
INSERT
操作およびUPDATE
操作に対する配列のバインド -
PL/SQLとOCIの境界でのパラメータの受渡し
ピース単位操作は、ポーリングまたはコールバックによって実行できます。これらの操作をサポートするために、次のOCI関数では、表8-1に示すLONG
データ型とLOBデータ型が受け入れられます。
-
OCIBindByName()
およびOCIBindByPos()
これらの関数を使用して、
INSERT
操作およびUPDATE
操作用にSQL文またはPL/SQLブロック内のプログラム変数とプレースホルダ間の対応付けを行います。 -
OCIBindDynamic()
このコールを使用して、
INSERT
操作またはUPDATE
操作用に動的にデータを割り当てるためのコールバックを登録します。 -
OCIStmtGetPieceInfo()
およびOCIStmtSetPieceInfo()
これらのコールを使用して、ピース単位操作のためのピース情報を取得または設定します。
親トピック: OCIにおけるLOB用のデータ・インタフェース
8.4.2 OCIにおけるLOBの定義
この項で説明するOCI関数は、LOB型をデータ型および出力バッファに関連付けます。
LOB用のデータ・インタフェースを使用すると、表8-1に示すように、次のOCI関数でLONGデータ型とLOBデータ型を受け入れることができます。
次の機能を使用できます
-
OCIDefineByPos()
このコールを使用して、
SELECT
リストにある項目を型および出力データ・バッファに対応付けます。 -
OCIDefineDynamic()
このコールを使用して、
OCIDefineByPos()
関数のコールでOCI_DYNAMIC_FETCH
モードが選択された場合、SELECT
操作に対してユーザー・コールバックを登録します。OCIDataServerLengthGet()
関数を使用すると、動的定義コールバックの使用中にLOB長を取得できます。
これらの関数をLOB型に使用すると、LOBロケータではなくLOBデータがバッファに選択されます。OCIでは、LOB用のデータ・インタフェースを使用して読み取る量を指定できないことに注意してください。指定できるのは、バッファ長のみです。バッファに収まる量のデータのみが読み取られ、データが切り捨てられます。
親トピック: OCIにおけるLOB用のデータ・インタフェース
8.4.3 LOB用データ・インタフェースでのOCIのマルチバイト文字セットの併用
この項では、OCIクライアントでマルチバイト文字セットを使用する場合のLOB用のデータ・インタフェースの機能について説明します。
クライアントの文字セットがマルチバイト形式の場合、データ・インタフェースに含まれる関数は、VARCHAR2
データ型の場合と同様にLOBデータ型を操作します。
-
マルチバイト文字セットでのピース単位フェッチの場合、マルチバイト文字が途中で切れることがあり、一部のバイトが1つのバッファの最後に、残りのバイトが次のバッファに入ることがあります。
-
通常のフェッチの場合、最後の文字のバイトの一部をバッファで保持できない場合には、バッファに収まるかぎりのバイトが戻されるため、部分的な文字にしかなりません。
親トピック: OCIにおけるLOB用のデータ・インタフェース
8.4.4 LOB長の取得
この項では、OCIアプリケーションでのLOB長のフェッチ方法について説明します。
LOBデータ長をフェッチするには、OCIServerDataLengthGet()
OCI関数を使用します。データ・インタフェースを使用してLOB列にアクセスすると、サーバーは最初にLOBデータ長を送信し、次にLOBデータを送信します。変換が行われる前に、サーバーはまずLOBデータ長を通信します。OCIクライアントにより、取得したLOB長がdefine
ハンドルに格納されます。OCIアプリケーションでは、OCIServerDataLengthGet()
関数を使用してLOB長にアクセスできます。
LOB長には、すべてのフェッチ・モード(単一ピース、ピース単位およびコールバック)でアクセスできます。また、サーバーとのラウンドトリップを発生させることなく、コールバックの内部でそれにアクセスできます。ただし、フェッチ操作の前は、それを使用しないでください。ピース単位操作またはコールバック操作の場合は、最初のピースがフェッチされた直後にそれを使用する必要があります。
親トピック: OCIにおけるLOB用のデータ・インタフェース
8.4.5 OCI関数を使用したLOB列のINSERTまたはUPDATEの実行
この項では、データ・インタフェースを使用してLOB列またはLOB属性のINSERT
操作またはUPDATE
操作を実行する各種の方法について説明します。
この項で説明する操作は、OCI環境を初期化して必要なハンドルをすべて割当て済であることを前提としています。
- 1つのピースでの単純なINSERT操作またはUPDATE操作の実行
この項では、LOB用のデータ・インタフェースを使用して、1つのピースで単純なINSERT
操作またはUPDATE
操作を実行するステップを示します。 - ポーリングによるピース単位INSERT操作およびUPDATE操作の使用
この項では、LOB用のデータ・インタフェースを使用して、ポーリングによるピース単位INSERT操作またはピース単位UPDATE操作を実行するステップを示します。 - コールバックによるピース単位INSERT操作およびUPDATE操作の実行
この項では、LOB用のデータ・インタフェースを使用して、コールバックによるピース単位INSERT
またはUPDATE
操作を実行するステップを示します。 - 配列のINSERT操作およびUPDATE操作の実行
LOB用のデータ・インタフェースを使用して配列のINSERT
操作またはUPDATE
操作を実行するには、この項で説明する方法のいずれかを使用します。
親トピック: OCIにおけるLOB用のデータ・インタフェース
8.4.5.1 1つのピースでの単純なINSERT操作またはUPDATE操作の実行
この項では、LOB用のデータ・インタフェースを使用して、単一のピースで単純なINSERT
操作またはUPDATE
操作を実行するステップを示します。
OCIStmtPrepare()
をOCI_DEFAULT
モードでコールして、文を準備します。OCIBindByName()
またはOCIBindbyPos()
をOCI_DEFAULT
モードでコールして、LOBを文字データまたはバイナリ・データとしてバインドするためにプレースホルダをバインドします。OCIStmtExecute()
をコールして、実際のINSERT
操作またはUPDATE
操作を実行します。
LOB列に対するINSERT
操作およびUPDATE
操作の文字データのバインドの例を次に示します。
void simple_insert()
{
/* Insert of data into LOB attributes is allowed. */
ub1 buffer[8000];
text *insert_sql = (text *)"INSERT INTO Print_media (ad_header) \
VALUES (adheader_typ(NULL, NULL, NULL,:1))";
OCIStmtPrepare(stmthp, errhp, insert_sql, strlen((char*)insert_sql),
(ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
OCIBindByPos(stmthp, &bindhp[0], errhp, 1, (dvoid *)buffer, 2000,
SQLT_LNG, 0, 0, 0, 0, 0, (ub4) OCI_DEFAULT);
OCIStmtExecute(svchp, stmthp, errhp, 1, 0, (const OCISnapshot*) 0,
(OCISnapshot*)0, OCI_DEFAULT);
}
8.4.5.2 ポーリングによるピース単位INSERT操作およびUPDATE操作の使用
この項では、LOB用のデータ・インタフェースを使用して、ポーリングによるピース単位INSERTまたはUPDATE操作を実行するステップを示します。
次の例に、LOB用のデータ・インタフェースとともにポーリングによるピース単位INSERT
を使用する例を示します。
void piecewise_insert()
{
text *sqlstmt = (text *)"INSERT INTO Print_media(Product_id, Ad_id,\
Ad_sourcetext) VALUES (:1, :2, :3)";
ub2 rcode;
ub1 piece, i;
word product_id = 2004;
word ad_id = 2;
ub4 buflen;
char buf[5000];
OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt),
(ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
OCIBindByPos(stmthp, &bndhp[0], errhp, (ub4) 1,
(dvoid *) &product_id, (sb4) sizeof(product_id), SQLT_INT,
(dvoid *) 0, (ub2 *)0, (ub2 *)0,
(ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT);
OCIBindByPos(stmthp, &bndhp[1], errhp, (ub4) 2,
(dvoid *) &ad_id, (sb4) sizeof(ad_id), SQLT_INT,
(dvoid *) 0, (ub2 *)0, (ub2 *)0,
(ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT);
OCIBindByPos(stmthp, &bndhp[2], errhp, (ub4) 3,
(dvoid *) 0, (sb4) 15000, SQLT_LNG,
(dvoid *) 0, (ub2 *)0, (ub2 *)0,
(ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC);
i = 0;
while (1)
{
i++;
retval = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
(CONST OCISnapshot*) 0, (OCISnapshot*) 0,
(ub4) OCI_DEFAULT);
switch(retval)
{
case OCI_NEED_DATA:
memset((void *)buf, (int)'A'+i, (size_t)5000);
buflen = 5000;
if (i == 1) piece = OCI_FIRST_PIECE;
else if (i == 3) piece = OCI_LAST_PIECE;
else piece = OCI_NEXT_PIECE;
if (OCIStmtSetPieceInfo((dvoid *)bndhp[2],
(ub4)OCI_HTYPE_BIND, errhp, (dvoid *)buf,
&buflen, piece, (dvoid *) 0, &rcode))
{
printf("ERROR: OCIStmtSetPieceInfo: %d \n", retval);
break;
}
break;
case OCI_SUCCESS:
break;
default:
printf( "oci exec returned %d \n", retval);
report_error(errhp);
retval = OCI_SUCCESS;
} /* end switch */
if (retval == OCI_SUCCESS)
break;
} /* end while(1) */
}
8.4.5.3 コールバックによるピース単位INSERT操作およびUPDATE操作の実行
この項では、LOB用のデータ・インタフェースを使用して、コールバックによるピース単位のINSERT
またはUPDATE
操作を実行するステップを示します。
OCIStmtPrepare()
をOCI_DEFAULT
モードでコールして、文を準備します。OCIBindByName()
またはOCIBindbyPos()
をOCI_DATA_AT_EXEC
モードでコールして、LOB列を文字データまたはバイナリ・データとしてバインドするためにプレースホルダをバインドします。OCIBindDynamic()
をコールしてコールバックを指定します。OCIStmtExecute()
をデフォルト・モードでコールします。
IN
バインドの場合、出力コールバックを指定する必要はありません。Oracle Database 21cリリース以降では、SQL/PLSQL操作へのOCIでの純粋なOUT
バインドの場合、入力コールバックを提供する必要はありません。
次の例に、コールバックによるピース単位INSERT
を使用したLOB列への文字データのバインドを示します。
void callback_insert()
{
word buflen = 15000;
word product_id = 2004;
word ad_id = 3;
text *sqlstmt = (text *) "INSERT INTO Print_media(Product_id, Ad_id,\
Ad_sourcetext) VALUES (:1, :2, :3)";
word pos = 3;
OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt),
(ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)
OCIBindByPos(stmthp, &bndhp[0], errhp, (ub4) 1,
(dvoid *) &product_id, (sb4) sizeof(product_id), SQLT_INT,
(dvoid *) 0, (ub2 *)0, (ub2 *)0,
(ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT);
OCIBindByPos(stmthp, &bndhp[1], errhp, (ub4) 2,
(dvoid *) &ad_id, (sb4) sizeof(ad_id), SQLT_INT,
(dvoid *) 0, (ub2 *)0, (ub2 *)0,
(ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT);
OCIBindByPos(stmthp, &bndhp[2], errhp, (ub4) 3,
(dvoid *) 0, (sb4) buflen, SQLT_CHR,
(dvoid *) 0, (ub2 *)0, (ub2 *)0,
(ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC);
OCIBindDynamic(bndhp[2], errhp, (dvoid *) (dvoid *) &pos,
insert_cbk, (dvoid *) 0, (OCICallbackOutBind) 0);
OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
(const OCISnapshot*) 0, (OCISnapshot*) 0,
(ub4) OCI_DEFAULT);
} /* end insert_data() */
/* Inbind callback to specify input data. */
static sb4 insert_cbk(dvoid *ctxp, OCIBind *bindp, ub4 iter, ub4 index,
dvoid **bufpp, ub4 *alenpp, ub1 *piecep, dvoid **indpp)
{
static int a = 0;
word j;
ub4 inpos = *((ub4 *)ctxp);
char buf[5000];
switch(inpos)
{
case 3:
memset((void *)buf, (int) 'A'+a, (size_t) 5000);
*bufpp = (dvoid *) buf;
*alenpp = 5000 ;
a++;
break;
default: printf("ERROR: invalid position number: %d\n", inpos);
}
*indpp = (dvoid *) 0;
*piecep = OCI_ONE_PIECE;
if (inpos == 3)
{
if (a<=1)
{
*piecep = OCI_FIRST_PIECE;
printf("Insert callback: 1st piece\n");
}
else if (a<3)
{
*piecep = OCI_NEXT_PIECE;
printf("Insert callback: %d'th piece\n", a);
}
else {
*piecep = OCI_LAST_PIECE;
printf("Insert callback: %d'th piece\n", a);
a = 0;
}
}
return OCI_CONTINUE;
}
8.4.5.4 配列のINSERT操作およびUPDATE操作の実行
LOB用のデータ・インタフェースを使用して配列INSERT
またはUPDATE
操作を実行するには、この項で説明する方法のいずれかを使用します。
OCIStmtExecute()
コールで、INSERT
操作またはUPDATE
操作をOCIBindArrayOfStruct()
とともに使用するか、iter
値が1より大きい反復回数(iter
)を指定します。配列のバインドを使用する場合は、LOBデータは、単一ピース、ピース単位またはコールバックを使用して挿入されるかどうかに関係なく、1回のラウンドトリップで複数行が挿入されます。
次の例に、配列のINSERT
操作を使用したLOB列への文字データのバインドを示します。
void array_insert()
{
ub4 i;
word buflen;
word arrbuf1[5];
word arrbuf2[5];
text arrbuf3[5][5000];
text *insstmt = (text *)"INSERT INTO Print_media(Product_id, Ad_id,\
Ad_sourcetext) VALUES (:PID, :AID, :SRCTXT)";
OCIStmtPrepare(stmthp, errhp, insstmt,
(ub4)strlen((char *)insstmt), (ub4) OCI_NTV_SYNTAX,
(ub4) OCI_DEFAULT);
OCIBindByName(stmthp, &bndhp[0], errhp,
(text *) ":PID", (sb4) strlen((char *) ":PID"),
(dvoid *) &arrbuf1[0], (sb4) sizeof(arrbuf1[0]), SQLT_INT,
(dvoid *) 0, (ub2 *)0, (ub2 *) 0,
(ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT);
OCIBindByName(stmthp, &bndhp[1], errhp,
(text *) ":AID", (sb4) strlen((char *) ":AID"),
(dvoid *) &arrbuf2[0], (sb4) sizeof(arrbuf2[0]), SQLT_INT,
(dvoid *) 0, (ub2 *)0, (ub2 *) 0,
(ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT);
OCIBindByName(stmthp, &bndhp[2], errhp,
(text *) ":SRCTXT", (sb4) strlen((char *) ":SRCTXT"),
(dvoid *) arrbuf3[0], (sb4) sizeof(arrbuf3[0]), SQLT_CHR,
(dvoid *) 0, (ub2 *) 0, (ub2 *) 0,
(ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT);
OCIBindArrayOfStruct(bndhp[0], errhp sizeof(arrbuf1[0]),
indsk, rlsk, rcsk);
OCIBindArrayOfStruct(bndhp[1], errhp, sizeof(arrbuf2[0]),
indsk, rlsk, rcsk);
OCIBindArrayOfStruct(bndhp[2], errhp, sizeof(arrbuf3[0]),
indsk, rlsk, rcsk);
for (i=0; i<5; i++)
{
arrbuf1[i] = 2004;
arrbuf2[i] = i+4;
memset((void *)arrbuf3[i], (int)'A'+i, (size_t)5000);
}
OCIStmtExecute(svchp, stmthp, errhp, (ub4) 5, (ub4) 0,
(const OCISnapshot*) 0, (OCISnapshot*) 0,
(ub4) OCI_DEFAULT);
}
8.4.6 OCIデータ・インタフェースを使用したLOBデータのフェッチ
この項では、データ・インタフェースを使用してOCIで永続LOBまたは一時LOBからデータをフェッチする方法について説明します。
- 1つのピースでの単純なフェッチ操作の実行
LOBのデータ・インタフェースを使用して、1つのピースのLOBに対して単純なフェッチ操作を実行するには、この項に示すステップに従います。 - ポーリングによるピース単位フェッチの実行
LOB用のデータ・インタフェースを使用して、ポーリングによるLOB列に対してピース単位フェッチ操作を実行するには、この項に示すステップに従います。 - コールバックによるピース単位の実行
LOB用のデータ・インタフェースを使用して、コールバックによるLOB列に対してピース単位フェッチ操作を実行するには、この項に示すステップに従います。 - 配列フェッチ操作の実行
LOBのデータ・インタフェースを使用してOCIで配列フェッチ操作を実行するには、この項で説明する方法のいずれかを使用します。
親トピック: OCIにおけるLOB用のデータ・インタフェース
8.4.6.1 1つのピースでの単純なフェッチ操作の実行
LOBのデータ・インタフェースを使用して、1つのピースのLOBに対して単純なフェッチ操作を実行するには、この項に示すステップに従います。
OCIStmtPrepare()
をOCI_DEFAULT
モードでコールして、SELECT
文を準備します。OCIDefineByPos()
をOCI_DEFAULT
モードでコールして、LOBを文字データまたはバイナリ・データとして定義するために、選択リストの位置を定義します。OCIStmtExecute()
をコールしてSELECT
文を実行します。OCIStmtFetch()
をコールして実際のフェッチを実行します。
次の例に、単純フェッチを使用した永続LOBまたは一時LOBの選択を示します。
void simple_fetch()
{
word retval;
text buf[15000];
/*
This statement returns a persistent LOB, but can be modified to return a temporary LOB
using the query 'SELECT SUBSTR(Ad_sourcetext,5) FROM Print_media WHERE Product_id = 2004'
*/
text *selstmt = (text *) "SELECT Ad_sourcetext FROM Print_media WHERE\
Product_id = 2004";
OCIStmtPrepare(stmthp, errhp, selstmt, (ub4)strlen((char *)selstmt),
(ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
retval = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, (ub4) 0,
(const OCISnapshot*) 0, (OCISnapshot*) 0,
(ub4) OCI_DEFAULT);
while (retval == OCI_SUCCESS || retval == OCI_SUCCESS_WITH_INFO)
{
OCIDefineByPos(stmthp, &defhp, errhp, (ub4) 1, (dvoid *) buf,
(sb4) sizeof(buf), (ub2) SQLT_CHR, (dvoid *) 0,
(ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT);
retval = OCIStmtFetch(stmthp, errhp, (ub4) 1,
(ub4) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT);
if (retval == OCI_SUCCESS || retval == OCI_SUCCESS_WITH_INFO)
printf("buf = %.*s\n", 15000, buf);
}
}
8.4.6.2 ポーリングによるピース単位のフェッチの実行
LOB用のデータ・インタフェースを使用して、ポーリングによるLOB列に対するピース単位フェッチ操作を実行するには、この項に示すステップに従います。
次の例に、ポーリングによるピース単位フェッチを使用した、文字バッファへのLOB列の選択を示します。
void piecewise_fetch()
{
text buf[15000];
ub4 buflen=5000;
word retval;
text *selstmt = (text *) "SELECT Ad_sourcetext FROM Print_media
WHERE Product_id = 2004 AND Ad_id = 2";
OCIStmtPrepare(stmthp, errhp, selstmt,
(ub4) strlen((char *)selstmt),
(ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
OCIDefineByPos(stmthp, &dfnhp, errhp, (ub4) 1,
(dvoid *) NULL, (sb4) 100000, SQLT_LNG,
(dvoid *) 0, (ub2 *) 0,
(ub2 *) 0, (ub4) OCI_DYNAMIC_FETCH);
retval = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, (ub4) 0,
(CONST OCISnapshot*) 0, (OCISnapshot*) 0,
(ub4) OCI_DEFAULT);
retval = OCIStmtFetch(stmthp, errhp, (ub4) 1 ,
(ub2) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT);
while (retval != OCI_NO_DATA && retval != OCI_SUCCESS)
{
ub1 piece;
ub4 iter;
ub4 idx;
genclr((void *)buf, 5000);
switch(retval)
{
case OCI_NEED_DATA:
OCIStmtGetPieceInfo(stmthp, errhp, &hdlptr, &hdltype,
&in_out, &iter, &idx, &piece);
buflen = 5000;
OCIStmtSetPieceInfo(hdlptr, hdltype, errhp,
(dvoid *) buf, &buflen, piece,
(CONST dvoid *) &indp1, (ub2 *) 0);
retval = OCI_NEED_DATA;
break;
default:
printf("ERROR: piece-wise fetching, %d\n", retval);
return;
} /* end switch */
retval = OCIStmtFetch(stmthp, errhp, (ub4) 1 ,
(ub2) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT);
printf("Data : %.5000s\n", buf);
} /* end while */
}
8.4.6.3 コールバックによるピース単位のフェッチの実行
この項にリストされているステップに従って、LOB用のデータ・インタフェースを使用して、コールバックによるLOB列に対するピース単位フェッチ操作を実行します。
OCIStmtPrepare()
をOCI_DEFAULT
モードでコールして、文を準備します。OCIDefinebyPos()
をOCI_DYNAMIC_FETCH
モードでコールして、LOB列を文字データまたはバイナリ・データとして定義するために、選択リストの位置を定義します。OCIStmtExecute()
をコールしてSELECT
文を実行します。OCIDefineDynamic()
をコールしてコールバックを指定します。OCIStmtFetch()
をデフォルト・モードでコールします。- コールバックの内部で、
OCIServerDataLengthGet()
を使用して最初のフェッチの間にLOB長を取得することもできます。この値を使用して、LOBデータを保持するためのバッファを割り当てることができます。
次の例に、コールバックによるピース単位フェッチを使用した、LOBバッファへのLOB列の選択を示します。
char buf[5000];
void callback_fetch()
{
word outpos = 1;
text *sqlstmt = (text *) "SELECT Ad_sourcetext FROM Print_media WHERE
Product_id = 2004 AND Ad_id = 3";
OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt),
(ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
OCIDefineByPos(stmthp, &dfnhp[0], errhp, (ub4) 1,
(dvoid *) 0, (sb4)3 * sizeof(buf), SQLT_CHR,
(dvoid *) 0, (ub2 *)0, (ub2 *)0,
(ub4) OCI_DYNAMIC_FETCH);
OCIDefineDynamic(dfnhp[0], errhp, (dvoid *) &outpos,
(OCICallbackDefine) fetch_cbk);
OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
(const OCISnapshot*) 0, (OCISnapshot*) 0,
(ub4) OCI_DEFAULT);
buf[ 4999 ] = '\0';
printf("Select callback: Last piece: %s\n", buf);
}
/* -------------------------------------------------------------- */
/* Fetch callback to specify buffers. */
/* -------------------------------------------------------------- */
static sb4 fetch_cbk(dvoid *ctxp, OCIDefine *dfnhp, ub4 iter, dvoid **bufpp,
ub4 **alenpp, ub1 *piecep, dvoid **indpp, ub2 **rcpp)
{
static int a = 0;
ub4 outpos = *((ub4 *)ctxp);
ub4 len = 5000;
switch(outpos)
{
case 1:
a ++;
*bufpp = (dvoid *) buf;
*alenpp = &len;
break;
default:
*bufpp = (dvoid *) 0;
*alenpp = (ub4 *) 0;
printf("ERROR: invalid position number: %d\n", outpos);
}
*indpp = (dvoid *) 0;
*rcpp = (ub2 *) 0;
buf[len] = '\0';
if (a<=1)
{
*piecep = OCI_FIRST_PIECE;
printf("Select callback: 0th piece\n");
}
else if (a<3)
{
*piecep = OCI_NEXT_PIECE;
printf("Select callback: %d'th piece: %s\n", a-1, buf);
}
else {
*piecep = OCI_LAST_PIECE;
printf("Select callback: %d'th piece: %s\n", a-1, buf);
a = 0;
}
return OCI_CONTINUE;
}
次の例に、コールバックによるピース単位フェッチを使用した、文字バッファへのLOB列の選択と、LOBデータ長のフェッチを示します。
#define MAX_BUF_SZ 1048576 /* Max allocation size = 1M */
char *buffer = NULL;
ub8 buf_len = 0;
/* Define callback function */
sb4 DefineCbk(void *cbctx, OCIDefine *defnhp, ub4 iter,
void **bufp, ub4 **alenp, ub1 *piecep,
void **indp, ub2 **rcodep)
{
static sword piece = 1;
boolean isValidLen = FALSE;
buf_len = 0;
if (piece == 1)
{
OCIServerDataLengthGet(defnhp, &isValidLen, (ub8 *) &buf_len,
(OCIError *)cbctx, 0);
if (buf_len > MAX_BUF_SZ)
buf_len = MAX_BUF_SZ;
buffer = (char *)malloc(buf_len);
*bufp = buffer;
*alenp = (ub4 *) &buf_len;
}
else
{
printf("Data = %s\n",buffer);
buf_len = MAX_BUF_SZ;
}
piece++;
return OCI_CONTINUE;
}
void define_callback()
{
text *sqlstmt = (text *)"select lobcol from lob_table";
OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen( sqlstmt),
(ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
OCIDefineByPos(stmthp, &defhp1, errhp, (ub4)1, (dvoid *)0,
(sb4) (10 * MAX_BUF_SZ), SQLT_STR, (dvoid *) 0,
(ub2 *) 0, (ub2 *) 0, (ub4)OCI_DYNAMIC_FETCH);
OCIDefineDynamic(defhp1,errhp, errhp,
(OCICallbackDefine)DefineCbk);
OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, (ub4) 0,
(CONST OCISnapshot *) 0, (OCISnapshot *) 0,
(ub4) OCI_DEFAULT);
OCIStmtFetch(stmthp, errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
buffer[buf_len] = '\0';
printf(" Data = %s\n",buffer);
if (buffer)
free(buffer);
}
8.4.6.4 配列フェッチ操作の実行
LOB用のデータ・インタフェースを使用してOCIで配列フェッチ操作を実行するには、この項で説明する方法のいずれかを使用します。
OCIStmtExecute()
コールで、次に説明する方法をOCIDefineArrayOfStruct()
とともに使用するか、iter
の値を使用して反復回数(iter
)を1より大きい値に指定します。配列の定義を使用する場合は、LOBデータは、単一ピース、ピース単位またはコールバックを使用してフェッチされるかどうかに関係なく、1回のラウンドトリップで複数行がフェッチされます。
次の例に、配列フェッチを使用した文字バッファへのLOB列の選択を示します。
void array_fetch()
{
word i;
text arrbuf[5][5000];
text *selstmt = (text *) "SELECT Ad_sourcetext FROM Print_media WHERE
Product_id = 2004 AND Ad_id >=4";
OCIStmtPrepare(stmthp, errhp, selstmt, (ub4)strlen((char *)selstmt),
(ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, (ub4) 0,
(const OCISnapshot*) 0, (OCISnapshot*) 0, (ub4) OCI_DEFAULT);
OCIDefineByPos(stmthp, &defhp1, errhp, (ub4) 1,
(dvoid *) arrbuf[0], (sb4) sizeof(arrbuf[0]),
(ub2) SQLT_CHR, (dvoid *) 0,
(ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT);
OCIDefineArrayOfStruct(dfnhp1, errhp, sizeof(arrbuf[0]), indsk,
rlsk, rcsk);
retval = OCIStmtFetch(stmthp, errhp, (ub4) 5,
(ub4) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT);
if (retval == OCI_SUCCESS || retval == OCI_SUCCESS_WITH_INFO)
{
printf("%.5000s\n", arrbuf[0]);
printf("%.5000s\n", arrbuf[1]);
printf("%.5000s\n", arrbuf[2]);
printf("%.5000s\n", arrbuf[3]);
printf("%.5000s\n", arrbuf[4]);
}
}
8.4.7 OCIからのPL/SQLバインドおよびCバインド
この項では、LOBに関してOCIからのPL/SQLおよびCバインドについて学習します。
OCIからPL/SQLプロシージャをコールして、IN
バインドまたはOUT
バインド(あるいはIN OUT
バインド)を行う場合、次のいずれかを行えます。
-
PL/SQLプロシージャの仮パラメータが
SQLT_CLOB
である場合、変数をSQLT_CHR
またはSQLT_LNG
としてバインドする。 -
仮パラメータが
SQLT_BLOB
である場合、変数をSQLT_BIN
またはSQLT_LBI
としてバインドする。
次に、有効な2つの例を示します。
begin foo(:1); end;形式でのPL/SQLアウトバインドのコール
begin foo(:1); end;形式でPL/SQLアウトバインドをコールする例を次に示します。
text *sqlstmt = (text *)"BEGIN get_lob(:c); END; " ;
call foo(:1);形式でのPL/SQLアウトバインドのコール
call foo(:1);形式でPL/SQLアウトバインドをコールする例を次に示します。
text *sqlstmt = (text *)"CALL get_lob(:c);" ;
どちらの例でも、プログラムの後半には次の文が含まれます。
OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT); curlen = 0; OCIBindByName(stmthp, &bndhp[3], errhp, (text *) ":c", (sb4) strlen((char *) ":c"), (dvoid *) buf5, (sb4) LONGLEN, SQLT_CHR, (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) 1, (ub4 *) &curlen, (ub4) OCI_DATA_AT_EXEC);
PL/SQLプロシージャget_lob()
を次に示します。
procedure get_lob(c INOUT CLOB) is -- This might have been column%type BEGIN ... /* The procedure body could be in PL/SQL or C*/ END;
親トピック: OCIにおけるLOB用のデータ・インタフェース