永続LOB用のデータ・インタフェースには、LOBデータ型を処理するように拡張された一連のJava API、PL/SQL APIおよびOCI APIが組み込まれています。これらのAPIは、当初はLONG、LONG RAWおよびVARCHAR2などのレガシー・データ型用に設計されましたが、表14-1と表14-2に示す対応するLOBデータ型にも使用できます。この2つの表で、「バインド型または定義型」列はレガシー・データ型を示し、「LOB列の型」列は対応するサポート対象のLOBデータ型を示します。LOB用のデータ・インタフェースを使用すると、対応するレガシー・データ型に格納されている場合と同様に、文字データとバイナリ・データをLOB列に格納して操作できます。
|
注意: データ・インタフェースは、オブジェクトの属性であるLOBのみでなくLOB列に対しても機能します。この章では、「LOB列」とはLOB列およびLOB属性を意味します。配列のバインドおよび定義インタフェースを使用すると、複数の行を1回のラウンドトリップで挿入および選択できます。 |
簡潔にするために、この章では文字データ型を中心に説明しますが、表14-1と表14-2に示す文字データ型とバイナリ・データ型のフル・セットにも同じ概念が適用されます。これらの表では、CLOBはNCLOBも意味しています。
永続LOB用のデータ・インタフェースを使用すると、次のメリットがあります。
アプリケーションですでにLONGデータ型を使用している場合は、そのアプリケーションをそのまま、または少し変更すればLOBデータ型を使用できます。そのためには、単に表のLONGデータ型の列をLOBデータ型の列に変換します。詳細は、第12章「LONGからLOBへの列の移行」を参照してください。
逐次アクセス技法を使用するOCIアプリケーションの場合は、パフォーマンスが向上します。データ・インタフェースを使用してピース単位のINSERTまたはフェッチを実行すると、OCILobRead2()やOCILobWrite2()などのOCI関数を使用する場合と同様のパフォーマンスが得られます。データ・インタフェースを使用すると、1回のOCIコールでLOBに4KBを超えるデータを挿入できるため、サーバーへのラウンドトリップを削減できます。
最初にLOBロケータをフェッチしてからOCILobRead2()をコールするかわりに、1回のOCIStmtFetch()コールでLOBデータを読み取ることができます。これにより、LOBデータを最初から読み取る場合のパフォーマンスが向上します。
配列のバインドおよび定義インタフェースを使用すると、LOBを含む複数の行を1回のラウンドトリップで挿入および選択できます。
このデータ・インタフェースを使用すると、表14-1に示すLONGデータ型とLOBデータ型を使用して、PL/SQLで次の操作を実行できます。
VARCHAR2、CHARまたはLONGなどのデータ型で格納された文字データをCLOB列にINSERTまたはUPDATEします。
RAWまたはLONG RAWなどのデータ型で格納されたバイナリ・データをBLOB列にINSERTまたはUPDATEします。
CLOB列でSELECT文を使用して、データをCHAR、LONGまたはVARCHAR2などの文字バッファ変数に選択します。
BLOB列でSELECT文を使用して、データをRAWやLONG RAWなどのバイナリ・バッファ変数に選択します。
CLOBとVARCHAR2、CHARまたはLONG変数の間で型間の割当て(暗黙的な型変換)を実行します。
BLOBとRAWまたはLONG RAW変数の間で型間の割当て(暗黙的な型変換)を実行します。
LONGデータ型を受け入れるように定義されたファンクションにLOBデータ型を渡すか、LOBデータ型を受け入れるように定義されたファンクションにLONGデータ型を渡します。たとえば、VARCHAR2、CHARまたはLONGなど、他のキャラクタ・タイプを受け入れるように定義されたファンクションに、CLOBインスタンスを渡すことができます。
INSTRやSUBSTRなどのVARCHAR2引数を受け入れる他のPL/SQLファンクションおよび演算子とともにCLOBを使用します。詳細なリストは、「SQLおよびPL/SQL組込みファンクションへのCLOBの受渡し」を参照してください。
|
注意: PL/SQLでLOB用のデータ・インタフェースをSELECT文とともに使用する場合、読み取る量は指定できません。指定できるのは、バッファ長のみです。バッファ長がLOBデータより短い場合は、データベースで例外が発生します。 |
この項では、永続LOB用のデータ・インタフェースを使用してLOB列またはLOB属性にアクセスする方法について説明します。
CLOB列およびBLOB列またはCLOB属性およびBLOB属性からのデータは、INSERT文、UPDATE文、SELECT文などの通常のSQL文を使用して参照できます。
PL/SQLには、ピース単位のINSERT、UPDATEまたはフェッチ用のルーチンがありません。そのため、LOB列またはLOB属性からアクセスできるデータ量は、文字バッファ・サイズの最大値によって制限されます。PL/SQLは文字バッファ・サイズを32KB - 1(32767バイト)までサポートします。このため、PL/SQLアプリケーションで永続LOB用のデータ・インタフェースを使用してアクセスできるLOBは、32KB未満に制限されます。
データ・インタフェースを使用して32KB - 1を超えるデータにアクセスする場合は、PL/SQLコードからOCIコールを実行して、ピース単位挿入およびフェッチ用のAPIを使用する必要があります。
データ・インタフェースを使用してLOB列またはLOB属性にアクセスする場合は、次のガイドラインに従ってください。
INSERT操作
VALUES句の通常のINSERT文を使用して、LOB列またはLOB属性を含む表にINSERTできます。LOB列のフィールドは、リテラル、文字データ型、バイナリ・データ型またはLOBロケータです。
UPDATE操作
LOB列またはLOB属性は、UPDATE... SET文によって全体を更新できます。SET句では、新しい値にリテラル、文字データ型、バイナリ・データ型またはLOBロケータを使用できます。
16進からRAWおよびRAWから16進への変換に関する4000バイトの制限
サイズが4000バイトを超えるデータの場合、データベースでは16進からRAWまたはRAWから16進への暗黙的な変換は実行されません。バッファのサイズが4000バイトを超える場合、文字データのバッファはバイナリ・データ型の列にバインドできず、バイナリ・データのバッファは文字データ型の列にバインドできません。この種のバインドを試みると、列データが4000バイトで切り捨てられます。
たとえば、サイズが4000バイトを超えるVARCHAR2バッファはLONG RAW列またはBLOB列にバインドできません。同様に、サイズが4000バイトを超えるRAWバッファはLONG列またはCLOB列にバインドできません。
SELECT操作
PL/SQLでは、LOB列またはLOB属性を選択して文字バッファまたはバイナリ・バッファに格納できます。LOB列またはLOB属性がバッファ・サイズより大きい場合、データはバッファに格納されず、例外が発生します。LOB列またはLOB属性は、LOBロケータとしても選択できます。
LOB列の場合は、暗黙的な割当てとパラメータの受渡しがサポートされます。表14-1および表14-2に示したデータ型の場合は、永続LOB用のデータ・インタフェースを使用して、キャラクタ・タイプを別のキャラクタ・タイプに、またはバイナリ型を他のバイナリ型に渡したり割り当てることができます。
暗黙的な割当ては、次の例に示すように、明示的に宣言された変数と、%TYPE属性を使用して既存の列の型を参照することで宣言された変数に対して機能します。この例では、t表のlong_col列がLONGからCLOB列に移行されたものとします。
CREATE TABLE t (long_col LONG); -- Alter this table to change LONG column to LOB DECLARE a VARCHAR2(100); b t.long_col%type; -- This variable changes from LONG to CLOB BEGIN SELECT * INTO b FROM t; a := b; -- This changes from "VARCHAR2 := LONG to VARCHAR2 := CLOB b := a; -- This changes from "LONG := VARCHAR2 to CLOB := VARCHAR2 END;
ファンクションとプロシージャの間で暗黙的なパラメータの受渡しが可能です。たとえば、仮パラメータがVARCHAR2として定義されているファンクションまたはプロシージャにCLOBを渡すことができます。
|
注意: LOB変数にVARCHAR2バッファを割り当てるよりも、VARCHAR2をLONG変数に割り当てる方が効率的です。これは、前者の場合は一時LOBを作成する必要があるためです。その結果、アプリケーションのパフォーマンスがやや低下します。 |
暗黙的なパラメータの受渡しは、文字データを受け入れるPL/SQL組込みファンクションの場合もサポートされます。たとえば、INSTRには、他の文字データのみでなくCLOBも使用できます。
VARCHAR2を受け入れるSQLまたはPL/SQL組込みファンクションは、すべて引数としてCLOBを受け入れることができます。同様に、LOBロケータを取るパラメータについては、どのDBMS_LOB APIにもVARCHAR2変数を渡すことができます。
PL/SQLでは、次の明示的な変換ファンクションにより、他のデータ型がCLOBおよびBLOBデータ型に変換されます。
TO_CLOB()は、LONG、VARCHAR2およびCHARをCLOBに変換します。
TO_BLOB()は、LONG RAWおよびRAWをBLOBに変換します。
変換ファンクションTO_CHAR()がCLOBをCHAR型に変換できることにも注意してください。
SQLからPL/SQLプロシージャまたはCプロシージャをコールする場合、4000バイトを超えるデータを含むバッファは許可されません。
PL/SQLからPL/SQLプロシージャまたはCプロシージャをコールできます。CHRが仮パラメータの場合、CLOBを実パラメータとして渡すことができます。またその逆も可能です。BLOBおよびRAWの場合も同様です。
これにはどのような場合があるかというと、たとえば、仮パラメータまたは実パラメータがアンカー型の場合、つまり変数がtable_name.column_name%type構文を使用して宣言されている場合です。
PL/SQLプロシージャまたはファンクションには、CLOBまたはVARCHAR2を仮パラメータとして指定できます。たとえば、PL/SQLプロシージャは次のいずれかのように指定できます。
仮パラメータがCLOBの場合:
CREATE OR REPLACE PROCEDURE get_lob(table_name IN VARCHAR2, lob INOUT CLOB) AS ... BEGIN ... END; /
仮パラメータがVARCHAR2の場合:
CREATE OR REPLACE PROCEDURE get_lob(table_name IN VARCHAR2, lob INOUT VARCHAR2) AS ... BEGIN ... END; /
コールするファンクションは次のいずれかのタイプです。
実パラメータがCHRの場合:
create procedure ...
declare
c VARCHAR2[200];
BEGIN
get_lob('table_name', c);
END;
実パラメータがCLOBの場合:
create procedure ...
declare
c CLOB;
BEGIN
get_lob('table_name', c);
END;
LOB列に対するINSERT操作とUPDATE操作では、すべてのサイズのバインドがサポートされます。1つのINSERT文またはUPDATE文で、任意のサイズの複数のバインドが可能です。
|
注意: 表の作成時には、LOB列のデフォルト値に指定できる長さが4000バイトに制限されています。 |
4000バイトを超えるデータをBLOBまたはCLOBにバインドし、そのデータがSQL演算子で構成される場合、結果のサイズは最大4000バイトに制限されます。
次の文では、LPADの結果が4000バイトに制限されているため、4000バイトのみ挿入されます。
INSERT INTO print_media (ad_sourcetext) VALUES (lpad('a', 5000, 'a'));
次の文では、LPADの結果が4000バイトに制限され、HEXからRAWへの暗黙的な変換によって2000バイトのRAWデータに変換されるため、2000バイトのみ挿入されます。
INSERT INTO print_media (ad_photo) VALUES (lpad('a', 5000, 'a'));
次の例に、SQL演算子の結果が4000バイトに制限されることを示します。
/* The following command inserts only 4000 bytes because the result of
* LPAD is limited to 4000 bytes */
INSERT INTO print_media(product_id, ad_id, ad_sourcetext)
VALUES (2004, 5, lpad('a', 5000, 'a'));
SELECT LENGTH(ad_sourcetext) FROM print_media
WHERE product_id=2004 AND ad_id=5;
ROLLBACK;
/* The following command inserts only 2000 bytes because the result of
* LPAD is limited to 4000 bytes, and the implicit hex to raw conversion
* converts it to 2000 bytes of RAW data. */
INSERT INTO print_media(product_id, ad_id, ad_composite)
VALUES (2004, 5, lpad('a', 5000, 'a'));
SELECT LENGTH(ad_composite) from print_media
WHERE product_id=2004 AND ad_id=5;
ROLLBAACK;
4000バイトを超えるバインドに対する制限事項を次に示します。
表にLONG列とLOB列の両方がある場合、LONG列またはLOB列のいずれかに4000バイトを超えるデータをバインドできますが、同一の文で両方にバインドすることはできません。
INSERT AS SELECT操作では、どのような長さのデータもLOB列にバインドできません。
LOB列を含む表に対する次のDML操作のパラレル実行がサポートされています。これらの操作がパラレル実行モードで実行されるのは、パーティション表に対して実行する場合のみです。LOB列を含む非パーティション表のDML文は、引き続きシリアル実行モードで実行されます。
INSERT AS SELECT
CREATE TABLE AS SELECT
DELETE
UPDATE
MERGE(条件付きUPDATEおよびINSERT)
複数表INSERT
|
関連項目: 『Oracle Database管理者ガイド』のパラレルSQL実行プロセスの管理に関する項を参照してください。 |
DECLARE
bigtext VARCHAR2(32767);
smalltext VARCHAR2(2000);
bigraw RAW (32767);
BEGIN
bigtext := LPAD('a', 32767, 'a');
smalltext := LPAD('a', 2000, 'a');
bigraw := utl_raw.cast_to_raw (bigtext);
/* Multiple long binds for LOB columns are allowed for INSERT: */
INSERT INTO print_media(product_id, ad_id, ad_sourcetext, ad_composite)
VALUES (2004, 1, bigtext, bigraw);
/* Single long bind for LOB columns is allowed for INSERT: */
INSERT INTO print_media (product_id, ad_id, ad_sourcetext)
VALUES (2005, 2, smalltext);
bigtext := LPAD('b', 32767, 'b');
smalltext := LPAD('b', 20, 'a');
bigraw := utl_raw.cast_to_raw (bigtext);
/* Multiple long binds for LOB columns are allowed for UPDATE: */
UPDATE print_media SET ad_sourcetext = bigtext, ad_composite = bigraw,
ad_finaltext = smalltext;
/* Single long bind for LOB columns is allowed for UPDATE: */
UPDATE print_media SET ad_sourcetext = smalltext, ad_finaltext = bigtext;
/* The following is NOT allowed because we are trying to insert more than
4000 bytes of data in a LONG and a LOB column: */
INSERT INTO print_media(product_id, ad_id, ad_sourcetext, press_release)
VALUES (2030, 3, bigtext, bigtext);
/* Insert of data into LOB attribute is allowed */
INSERT INTO print_media(product_id, ad_id, ad_header)
VALUES (2049, 4, adheader_typ(null, null, null, bigraw));
/* The following is not allowed because we try to perform INSERT AS
SELECT data INTO LOB */
INSERT INTO print_media(product_id, ad_id, ad_sourcetext)
SELECT 2056, 5, bigtext FROM dual;
END;
/
LOBに対するINSERT文およびUPDATE文の使用方法は、LONGに対する使用方法と同じです。次に例を示します。
DECLARE
ad_buffer VARCHAR2(100);
BEGIN
INSERT INTO print_media(product_id, ad_id, ad_sourcetext)
VALUES(2004, 5, 'Source for advertisement 1');
UPDATE print_media SET ad_sourcetext= 'Source for advertisement 2'
WHERE product_id=2004 AND ad_id=5;
/* This will get the LOB column if it is up to 100 bytes, otherwise it will
* raise an exception */
SELECT ad_sourcetext INTO ad_buffer FROM print_media
WHERE product_id=2004 AND ad_id=5;
END;
/
LOB用のデータ・インタフェースを使用すると、次の例に示すように暗黙的な割当てとパラメータの受渡しが可能です。
CREATE TABLE t (clob_col CLOB, blob_col BLOB);
INSERT INTO t VALUES('abcdefg', 'aaaaaa');
DECLARE
var_buf VARCHAR2(100);
clob_buf CLOB;
raw_buf RAW(100);
blob_buf BLOB;
BEGIN
SELECT * INTO clob_buf, blob_buf FROM t;
var_buf := clob_buf;
clob_buf:= var_buf;
raw_buf := blob_buf;
blob_buf := raw_buf;
END;
/
CREATE OR REPLACE PROCEDURE FOO ( a IN OUT CLOB) IS
BEGIN
-- Any procedure body
a := 'abc';
END;
/
CREATE OR REPLACE PROCEDURE BAR (b IN OUT VARCHAR2) IS
BEGIN
-- Any procedure body
b := 'xyz';
END;
/
DECLARE
a VARCHAR2(100) := '1234567';
b CLOB;
BEGIN
FOO(a);
SELECT clob_col INTO b FROM t;
BAR(b);
END;
/
この例では、LOB用のデータ・インタフェースを使用した、PL/SQL組込みファンクションでのCLOBの使用を示します。
DECLARE
my_ad CLOB;
revised_ad CLOB;
myGist VARCHAR2(100):= 'This is my gist.';
revisedGist VARCHAR2(100);
BEGIN
INSERT INTO print_media (product_id, ad_id, ad_sourcetext)
VALUES (2004, 5, 'Source for advertisement 1');
-- select a CLOB column into a CLOB variable
SELECT ad_sourcetext INTO my_ad FROM print_media
WHERE product_id=2004 AND ad_id=5;
-- perform VARCHAR2 operations on a CLOB variable
revised_ad := UPPER(SUBSTR(my_ad, 1, 20));
-- revised_ad is a temporary LOB
-- Concat a VARCHAR2 at the end of a CLOB
revised_ad := revised_ad || myGist;
-- The following statement will raise an error if my_ad is
-- longer than 100 bytes
myGist := my_ad;
END;
/
この項では、永続LOB用のデータ・インタフェースに組み込まれているOCI関数について説明します。この種のOCI関数は、LONGデータ型の場合と同様にLOBデータ型にも機能します。この種の関数を使用すると、文字データまたはバイナリ・データを格納する他のデータ型に使用するのと同じ方法で、OCIでLOBに対してINSERT、UPDATE、フェッチ、バインドおよび定義操作を実行できます。
|
注意: 配列のバインドおよび定義インタフェースを使用すると、LOBを含む複数の行を1回のラウンドトリップで挿入および選択できます。 |
|
関連項目: 『Oracle Call Interfaceプログラマーズ・ガイド』のOCIにおけるランタイム・データ割当てとピース単位操作に関する項 |
次の操作でLOBデータ型をバインドできます。
INSERT操作およびUPDATE操作に対する標準、ピース単位およびコールバックのバインド
INSERT操作およびUPDATE操作に対する配列のバインド
PL/SQLとOCIの境界でのパラメータの受渡し
ピース単位操作は、ポーリングまたはコールバックによって実行できます。これらの操作をサポートするために、次のOCI関数は表14-2に示すLONGデータ型とLOBデータ型を受け入れます。
OCIBindByName()およびOCIBindByPos()
これらの関数を使用して、INSERT操作およびUPDATE操作用にSQL文またはPL/SQLブロック内のプログラム変数とプレースホルダ間の対応付けを行います。
OCIBindDynamic()
このコールを使用して、INSERT操作またはUPDATE操作用に動的にデータを割り当てるためのコールバックを登録します。
OCIStmtGetPieceInfo()およびOCIStmtSetPieceInfo()
これらのコールを使用して、ピース単位操作のためのピース情報を取得または設定します。
永続LOB用のデータ・インタフェースを使用すると、次のOCI関数で表14-2に示すLONGデータ型とLOBデータ型を受け入れることができます。
OCIDefineByPos()
このコールを使用して、SELECTリストにある項目を型および出力データ・バッファに対応付けます。
OCIDefineDynamic()
このコールを使用して、OCIDefineByPos()関数のコールでOCI_DYNAMIC_FETCHモードが選択された場合、SELECT操作に対してユーザー・コールバックを登録します。
これらの関数をLOB型に使用すると、LOBロケータではなくLOBデータがバッファに選択されます。OCIでは、LOB用のデータ・インタフェースを使用して読み取る量を指定できないことに注意してください。指定できるのは、バッファ長のみです。バッファに収まる量のデータのみが読み取られ、データが切り捨てられます。
クライアントのキャラクタ・セットがマルチバイト形式の場合、データ・インタフェースに組み込まれている関数は、次のように、LONGデータ型の場合と同様にLOBデータ型を操作します。
マルチバイト・キャラクタ・セットでのピース単位フェッチでは、マルチバイト・キャラクタを2つに分割して、前半のバイトを一方のバッファの終わりに格納し、後半のバイトを次のバッファに格納できます。
標準のフェッチでは、最後の文字の一部のバイトをバッファに格納できない場合、Oracleはバッファに格納可能なサイズのバイト(部分的な文字)を戻します。
この項では、データ・インタフェースを使用してLOB列またはLOB属性のINSERT操作またはUPDATE操作を実行する各種の方法について説明します。この項で説明する操作は、OCI環境を初期化して必要なハンドルをすべて割当て済であることを前提としています。
永続LOB用のデータ・インタフェースを使用して、1つのピースで単純なINSERT操作またはUPDATE操作を実行する手順は、次のとおりです。
OCIStmtPrepare()をOCI_DEFAULTモードでコールして、文を準備します。
OCIBindByName()またはOCIBindbyPos()をOCI_DEFAULTモードでコールして、LOBを文字データまたはバイナリ・データとしてバインドするためにプレースホルダをバインドします。
OCIStmtExecute()をコールして、実際のINSERT操作またはUPDATE操作を実行します。
永続LOB用のデータ・インタフェースを使用して、ポーリングによりピース単位のINSERT操作またはUPDATE操作を実行する手順は、次のとおりです。
OCIStmtPrepare()をOCI_DEFAULTモードでコールして、文を準備します。
OCIBindByName()またはOCIBindbyPos()をOCI_DATA_AT_EXECモードでコールして、LOBを文字データまたはバイナリ・データとしてバインドします。
OCIStmtExecute()をデフォルト・モードでコールします。OCIStmtExecute()から戻される値がOCI_NEED_DATAの間は、ループ内で次の各手順を実行します。OCIStmtExecute()から値OCI_SUCCESSが戻された場合は、ループを終了します。
OCIStmtGetPieceInfo()をコールして、挿入するピースの情報を取り出します。
OCIStmtSetPieceInfo()をコールして、挿入するピースの情報を設定します。
永続LOB用のデータ・インタフェースを使用して、コールバックによりピース単位のINSERT操作またはUPDATE操作を実行する手順は、次のとおりです。
OCIStmtPrepare()をOCI_DEFAULTモードでコールして、文を準備します。
OCIBindByName()またはOCIBindbyPos()をOCI_DATA_AT_EXECモードでコールして、LOB列を文字データまたはバイナリ・データとしてバインドするためにプレースホルダをバインドします。
OCIBindDynamic()をコールしてコールバックを指定します。
OCIStmtExecute()をデフォルト・モードでコールします。
この項では、永続LOB用のデータ・インタフェースを使用して、OCIでLOB列またはLOB属性からデータをフェッチする方法について説明します。
永続LOB用のデータ・インタフェースを使用し、1つのピースでLOBに対して単純なフェッチ操作を実行する手順は、次のとおりです。
OCIStmtPrepare()をOCI_DEFAULTモードでコールして、SELECT文を準備します。
OCIDefineByPos()をOCI_DEFAULTモードでコールして、LOBを文字データまたはバイナリ・データとして定義するために、選択リストの位置を定義します。
OCIStmtExecute()をコールしてSELECT文を実行します。
OCIStmtFetch()をコールして実際のフェッチを実行します。
LOB用のデータ・インタフェースを使用し、LOB列に対してポーリングによるピース単位フェッチ操作を実行する手順は、次のとおりです。
OCIStmtPrepare()をOCI_DEFAULTモードでコールして、SELECT文を準備します。
OCIDefineByPos()をOCI_DYNAMIC_FETCHモードでコールして、LOB列を文字データまたはバイナリ・データとして定義するために、選択リストの位置を定義します。
OCIStmtExecute()をコールしてSELECT文を実行します。
OCIStmtFetch()をデフォルト・モードでコールします。OCIStmtFetch()から戻される値がOCI_NEED_DATAの間は、ループ内で次の各手順を実行します。OCIStmtFetch()から値OCI_SUCCESSが戻された場合は、ループを終了します。
OCIStmtGetPieceInfo()をコールして、フェッチするピースの情報を取り出します。
OCIStmtSetPieceInfo()をコールして、フェッチするピースの情報を設定します。
永続LOB用のデータ・インタフェースを使用し、LOB列に対してコールバックによるピース単位フェッチ操作を実行する手順は、次のとおりです。
OCIStmtPrepare()をOCI_DEFAULTモードでコールして、文を準備します。
OCIDefineByPos()をOCI_DYNAMIC_FETCHモードでコールして、LOB列を文字データまたはバイナリ・データとして定義するために、選択リストの位置を定義します。
OCIStmtExecute()をコールしてSELECT文を実行します。
OCIDefineDynamic()をコールしてコールバックを指定します。
OCIStmtFetch()をデフォルト・モードでコールします。
OCIからPL/SQLプロシージャをコールして、インバインドまたはアウトバインド(あるいはその両方)を行う場合、次のいずれかを行えます。
PL/SQLプロシージャの仮パラメータがSQLT_CLOBである場合、変数をSQLT_CHRまたはSQLT_LNGとしてバインドする。
仮パラメータがSQLT_BLOBである場合、変数をSQLT_BINまたはSQLT_LBIとしてバインドする。
次に、有効な2つの例を示します。
begin foo(:1); end;形式でPL/SQLアウトバインドをコールする例を次に示します。
text *sqlstmt = (text *)"BEGIN get_lob(:c); END; " ;
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;
void insert3()
{
/* Insert of data into LOB attributes is allowed. */
ub1 buffer[8000];
text *insert_sql = (text *)"INSERT INTO Print_media (ad_header) \
VALUES (adheader_typ(NULL, NULL, NULL,:1))";
OCIStmtPrepare(stmthp, errhp, insert_sql, strlen((char*)insert_sql),
(ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
OCIBindByPos(stmthp, &bindhp[0], errhp, 1, (dvoid *)buffer, 2000,
SQLT_LNG, 0, 0, 0, 0, 0, (ub4) OCI_DEFAULT);
OCIStmtExecute(svchp, stmthp, errhp, 1, 0, (const OCISnapshot*) 0,
(OCISnapshot*)0, OCI_DEFAULT);
}
LOB用のデータ・インタフェースを使用すると、OCIからのLOBのPL/SQLバインドを次のように使用できます。OCIからPL/SQLプロシージャをコールして、IN、OUTまたはIN OUTバインドを実行すると、PL/SQLプロシージャの仮パラメータがSQLT_CLOBである場合、変数をSQLT_CHRとしてバインドできます。
|
注意: CプロシージャはPL/SQLスタブにラップされています。そのため、OCIアプリケーションは常にPL/SQLスタブをコールします。 |
OCIをコールするプログラムでは、次のような場合が考えられます。
次に例を示します。
text *sqlstmt = (text *)"BEGIN PKG1.P5 (:c); END; " ;
次に例を示します。
text *sqlstmt = (text *)"CALL PKG1.P5( :c );" ;
どちらの例でも、プログラムの後半は次のようになります。
OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt),
(ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
curlen = 0;
OCIBindByName(stmthp, &bndhp[3], errhp,
(text *) ":c4", (sb4) strlen((char *) ":c"),
(dvoid *) buf5, (sb4) LONGLEN, SQLT_CHR,
(dvoid *) 0, (ub2 *) 0, (ub2 *) 0,
(ub4) 1, (ub4 *) &curlen, (ub4) OCI_DATA_AT_EXEC);
OCIStmtExecute(svchp, stmthp, errhp,(ub4) 0,(ub4) 0, (const OCISnapshot*) 0,
(OCISnapshot*) 0,(ub4) OCI_DEFAULT);
PL/SQLプロシージャPKG1.P5を次に示します。
CREATE OR REPLACE PACKAGE BODY pkg1 AS
...
procedure p5 (c OUT CLOB) is
-- This might have been table%rowtype (so it is CLOB now)
BEGIN
...
END p5;
END pkg1;
次の例に、LOB列の文字データのバインドを示します。
void simple_insert()
{
word buflen;
text buf[5000];
text *insstmt = (text *) "INSERT INTO Print_media(Product_id, Ad_id,\
Ad_sourcetext) VALUES (2004, 1, :SRCTXT)";
OCIStmtPrepare(stmthp, errhp, insstmt, (ub4)strlen((char *)insstmt),
(ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
OCIBindByName(stmthp, &bndhp[0], errhp,
(text *) ":SRCTXT", (sb4) strlen((char *) ":SRCTXT"),
(dvoid *) buf, (sb4) sizeof(buf), SQLT_CHR,
(dvoid *) 0, (ub2 *) 0, (ub2 *) 0,
(ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT);
memset((void *)buf, (int)'A', (size_t)5000);
OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
(const OCISnapshot*) 0, (OCISnapshot*) 0, (ub4) OCI_DEFAULT);
}
次の例に、LOB用のデータ・インタフェースとともにポーリングによるピース単位INSERTを使用する例を示します。
void piecewise_insert()
{
text *sqlstmt = (text *)"INSERT INTO Print_media(Product_id, Ad_id,\
Ad_sourcetext) VALUES (:1, :2, :3)";
ub2 rcode;
ub1 piece, i;
word product_id = 2004;
word ad_id = 2;
ub4 buflen;
char buf[5000];
OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt),
(ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
OCIBindByPos(stmthp, &bndhp[0], errhp, (ub4) 1,
(dvoid *) &product_id, (sb4) sizeof(product_id), SQLT_INT,
(dvoid *) 0, (ub2 *)0, (ub2 *)0,
(ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT);
OCIBindByPos(stmthp, &bndhp[1], errhp, (ub4) 2,
(dvoid *) &ad_id, (sb4) sizeof(ad_id), SQLT_INT,
(dvoid *) 0, (ub2 *)0, (ub2 *)0,
(ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT);
OCIBindByPos(stmthp, &bndhp[2], errhp, (ub4) 3,
(dvoid *) 0, (sb4) 15000, SQLT_LNG,
(dvoid *) 0, (ub2 *)0, (ub2 *)0,
(ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC);
i = 0;
while (1)
{
i++;
retval = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
(CONST OCISnapshot*) 0, (OCISnapshot*) 0,
(ub4) OCI_DEFAULT);
switch(retval)
{
case OCI_NEED_DATA:
memset((void *)buf, (int)'A'+i, (size_t)5000);
buflen = 5000;
if (i == 1) piece = OCI_FIRST_PIECE;
else if (i == 3) piece = OCI_LAST_PIECE;
else piece = OCI_NEXT_PIECE;
if (OCIStmtSetPieceInfo((dvoid *)bndhp[2],
(ub4)OCI_HTYPE_BIND, errhp, (dvoid *)buf,
&buflen, piece, (dvoid *) 0, &rcode))
{
printf("ERROR: OCIStmtSetPieceInfo: %d \n", retval);
break;
}
break;
case OCI_SUCCESS:
break;
default:
printf( "oci exec returned %d \n", retval);
report_error(errhp);
retval = OCI_SUCCESS;
} /* end switch */
if (retval == OCI_SUCCESS)
break;
} /* end while(1) */
}
次の例に、コールバックによるピース単位INSERTを使用する場合の、LOB列へのLONGデータのバインドを示します。
void callback_insert()
{
word buflen = 15000;
word product_id = 2004;
word ad_id = 3;
text *sqlstmt = (text *) "INSERT INTO Print_media(Product_id, Ad_id,\
Ad_sourcetext) VALUES (:1, :2, :3)";
word pos = 3;
OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt),
(ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)
OCIBindByPos(stmthp, &bndhp[0], errhp, (ub4) 1,
(dvoid *) &product_id, (sb4) sizeof(product_id), SQLT_INT,
(dvoid *) 0, (ub2 *)0, (ub2 *)0,
(ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT);
OCIBindByPos(stmthp, &bndhp[1], errhp, (ub4) 2,
(dvoid *) &ad_id, (sb4) sizeof(ad_id), SQLT_INT,
(dvoid *) 0, (ub2 *)0, (ub2 *)0,
(ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT);
OCIBindByPos(stmthp, &bndhp[2], errhp, (ub4) 3,
(dvoid *) 0, (sb4) buflen, SQLT_CHR,
(dvoid *) 0, (ub2 *)0, (ub2 *)0,
(ub4) 0, (ub4 *) 0, (ub4) OCI_DATA_AT_EXEC);
OCIBindDynamic(bndhp[2], errhp, (dvoid *) (dvoid *) &pos,
insert_cbk, (dvoid *) 0, (OCICallbackOutBind) 0);
OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
(const OCISnapshot*) 0, (OCISnapshot*) 0,
(ub4) OCI_DEFAULT);
} /* end insert_data() */
/* Inbind callback to specify input data. */
static sb4 insert_cbk(dvoid *ctxp, OCIBind *bindp, ub4 iter, ub4 index,
dvoid **bufpp, ub4 *alenpp, ub1 *piecep, dvoid **indpp)
{
static int a = 0;
word j;
ub4 inpos = *((ub4 *)ctxp);
char buf[5000];
switch(inpos)
{
case 3:
memset((void *)buf, (int) 'A'+a, (size_t) 5000);
*bufpp = (dvoid *) buf;
*alenpp = 5000 ;
a++;
break;
default: printf("ERROR: invalid position number: %d\n", inpos);
}
*indpp = (dvoid *) 0;
*piecep = OCI_ONE_PIECE;
if (inpos == 3)
{
if (a<=1)
{
*piecep = OCI_FIRST_PIECE;
printf("Insert callback: 1st piece\n");
}
else if (a<3)
{
*piecep = OCI_NEXT_PIECE;
printf("Insert callback: %d'th piece\n", a);
}
else {
*piecep = OCI_LAST_PIECE;
printf("Insert callback: %d'th piece\n", a);
a = 0;
}
}
return OCI_CONTINUE;
}
次の例に、配列のINSERT操作を使用したLOB列への文字データのバインドを示します。
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);
}
次の例に、単純フェッチを使用したLOB列の選択を示します。
void simple_fetch()
{
word retval;
text buf[15000];
text *selstmt = (text *) "SELECT Ad_sourcetext FROM Print_media WHERE\
Product_id = 2004";
OCIStmtPrepare(stmthp, errhp, selstmt, (ub4)strlen((char *)selstmt),
(ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
retval = OCIStmtExecute(svchp, stmthp, errhp, (ub4) 0, (ub4) 0,
(const OCISnapshot*) 0, (OCISnapshot*) 0,
(ub4) OCI_DEFAULT);
while (retval == OCI_SUCCESS || retval == OCI_SUCCESS_WITH_INFO)
{
OCIDefineByPos(stmthp, &defhp, errhp, (ub4) 1, (dvoid *) buf,
(sb4) sizeof(buf), (ub2) SQLT_CHR, (dvoid *) 0,
(ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT);
retval = OCIStmtFetch(stmthp, errhp, (ub4) 1,
(ub4) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT);
if (retval == OCI_SUCCESS || retval == OCI_SUCCESS_WITH_INFO)
printf("buf = %.*s\n", 15000, buf);
}
}
次の例に、ポーリングによるピース単位フェッチを使用した、LONGバッファへのLOB列の選択を示します。
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 */
}
次の例に、コールバックによるピース単位フェッチを使用した、LOBバッファへのLONG列の選択を示します。
char buf[5000];
void callback_fetch()
{
word outpos = 1;
text *sqlstmt = (text *) "SELECT Ad_sourcetext FROM Print_media WHERE\
Product_id = 2004 AND Ad_id = 3";
OCIStmtPrepare(stmthp, errhp, sqlstmt, (ub4)strlen((char *)sqlstmt),
(ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);
OCIDefineByPos(stmthp, &dfnhp[0], errhp, (ub4) 1,
(dvoid *) 0, (sb4)3 * sizeof(buf), SQLT_CHR,
(dvoid *) 0, (ub2 *)0, (ub2 *)0,
(ub4) OCI_DYNAMIC_FETCH);
OCIDefineDynamic(dfnhp[0], errhp, (dvoid *) &outpos,
(OCICallbackDefine) fetch_cbk);
OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
(const OCISnapshot*) 0, (OCISnapshot*) 0,
(ub4) OCI_DEFAULT);
buf[ 4999 ] = '\0';
printf("Select callback: Last piece: %s\n", buf);
}
/* -------------------------------------------------------------- */
/* Fetch callback to specify buffers. */
/* -------------------------------------------------------------- */
static sb4 fetch_cbk(dvoid *ctxp, OCIDefine *dfnhp, ub4 iter, dvoid **bufpp,
ub4 **alenpp, ub1 *piecep, dvoid **indpp, ub2 **rcpp)
{
static int a = 0;
ub4 outpos = *((ub4 *)ctxp);
ub4 len = 5000;
switch(outpos)
{
case 1:
a ++;
*bufpp = (dvoid *) buf;
*alenpp = &len;
break;
default:
*bufpp = (dvoid *) 0;
*alenpp = (ub4 *) 0;
printf("ERROR: invalid position number: %d\n", outpos);
}
*indpp = (dvoid *) 0;
*rcpp = (ub2 *) 0;
buf[len] = '\0';
if (a<=1)
{
*piecep = OCI_FIRST_PIECE;
printf("Select callback: 0th piece\n");
}
else if (a<3)
{
*piecep = OCI_NEXT_PIECE;
printf("Select callback: %d'th piece: %s\n", a-1, buf);
}
else {
*piecep = OCI_LAST_PIECE;
printf("Select callback: %d'th piece: %s\n", a-1, buf);
a = 0;
}
return OCI_CONTINUE;
}
次の例に、配列フェッチを使用した、LONGバッファへのLOB列の選択を示します。
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]);
}
}
CLOBデータおよびBLOBデータの読取りおよび書込みは、LONGデータおよびLONG RAWデータの場合と同じストリーミング・メカニズムを使用して行うこともできます。読み取る場合は、列でdefineColumnType(nn, Types.LONGVARCHAR)またはdefineColumnType(nn, Types.LONGVARBINARY)を使用します。これにより、LONGまたはLONG RAW列の場合と同様に、データに直接ストリームが生成されます。PreparedStatementへの入力には、BLOBまたはCLOBパラメータに対してsetBinaryStream()、setCharacterStream()またはsetAsciiStream()を使用できます。これらの方法では、ストリーム・インタフェースを使用して、ストリーム内のデータからデータベース内にLOBを作成します。これら両方の技法によってデータベースのラウンドトリップが削減され、場合によってはパフォーマンスが向上します。適用される大幅な制限については、http://www.oracle.com/technology/でストリーム・データに関するJavadocを参照してください。
『Oracle Database JDBC開発者ガイドおよびリファレンス』で、次を参照してください。
|
関連項目:
|
リモートLOBの挿入、更新および選択を行うためのデータ・インタフェース(dblinkを介したアクセス)は、Oracle Database 10g リリース2以上でサポートされています。次の項に示す例は、2つのスキーマ、dbs1およびdbs2で作成されたprint_media表についてのものです。例で使用されている表のCLOB列は、ad_finaltextです。次の項に示すPL/SQL、OCIおよびJavaについての例では、この1つの列に対してバインドおよび定義を使用していますが、複数の列にアクセスすることも可能です。次に、サポートされている機能とその制限を示します。
CLOBをCHARまたはNCHARとして、NCLOBをCHARまたはNCHARとして定義できます。CLOBおよびNCLOBは、LONGとして定義できます。BLOBは、RAWまたはLONG RAWとして定義できます。
配列のバインドおよび定義はサポートされています。
複数のデータベースを使用する問合せはサポートされていません。
SELECT t1.lobcol, a2.lobcol FROM t1, t2.lobcol@dbs2 a2 WHERE LENGTH(t1.lobcol) = LENGTH(a2.lobcol);
次の問合せもサポートされていません(PL/SQLブロック内)。
SELECT t1.lobcol INTO varchar_buf1 FROM t1@dbs1 UNION ALL SELECT t2.lobcol INTO varchar_buf2 FROM t2@dbs2;
リモートの永続LOB列に移動するデータに対するバインドおよび定義のみがサポートされているため、リモートLOBに対してCHARデータがバインドまたは定義されているPL/SQLで渡されるパラメータは、サポートされていないリモートの一時LOBが発生する可能性があるので許可されません。次の文ではすべて、エラーが生成されます。
SELECT foo() INTO varchar_buf FROM table1@dbs2; -- foo returns a LOB SELECT foo()@dbs INTO char_val FROM DUAL; -- foo returns a LOB SELECT XMLType().getclobval INTO varchar_buf FROM table1@dbs2;
リモート・オブジェクトが次のようなビューである場合。
CREATE VIEW v AS SELECT foo() a FROM ... ; -- foo returns a LOB /* The local database then tries to get the CLOB data and returns an error */ SELECT a INTO varchar_buf FROM v@dbs2;
これによってサポートされていないリモートの一時LOBが発生するため、エラーが戻されます。
RETURNING INTOでは、CHARとCLOBの間の暗黙的な変換はサポートされていません。
実引数がLOB型であり、リモート引数がVARCHAR2、NVARCHAR2、CHAR、NCHARまたはRAWである場合、PL/SQLパラメータの受渡しは許可されません。
PL/SQLにおけるデータ・インタフェースでは、サイズが32KB未満のデータのみがサポートされています。次にPL/SQLの例を示します。
CONNECT pm declare my_ad varchar(6000) := lpad('b', 6000, 'b'); BEGIN INSERT INTO print_media@dbs2(product_id, ad_id, ad_finaltext) VALUES (10000, 10, my_ad); -- Reset the buffer value my_ad := 'a'; SELECT ad_finaltext INTO my_ad FROM print_media@dbs2 WHERE product_id = 10000; END; /
ad_finaltextがCLOBではなくBLOB列である場合、my_adはRAW型である必要があります。LOBのサイズが32KB - 1を超えている場合、PL/SQLでは切捨てエラーが発生し、バッファの内容は未定義になります。
OCIにおけるデータ・インタフェースでは、サイズが2GB未満(sb4として宣言された変数の可能な最大値)のデータのみがサポートされています。次の疑似コードは、OCIプログラムの一部として拡張できます。
... text *sql = (text *)"insert into print_media@dbs2 (product_id, ad_id, ad_finaltext) values (:1, :2, :3)"; OCIStmtPrepare(...); OCIBindByPos(...); /* Bind data for positions 1 and 2 * which are independent of LOB */ OCIBindByPos(stmthp, &bndhp[2], errhp, (ub4) 3, (dvoid *) charbuf1, (sb4) len_charbuf1, SQLT_CHR, (dvoid *) 0, (ub2 *)0, (ub2 *)0, 0, 0, OCI_DEFAULT); OCIStmtExecute(...); ... text *sql = (text *)"select ad_finaltext from print_media@dbs2 where product_id = 10000"; OCIStmtPrepare(...); OCIDefineByPos(stmthp, &dfnhp[2], errhp, (ub4) 1, (dvoid *) charbuf2, (sb4) len_charbuf2, SQLT_CHR, (dvoid *) 0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT); OCIStmtExecute(...); ...
ad_finaltextがCLOBではなくBLOBである場合、SQLT_BIN型を使用してバインドおよび定義します。LOBのサイズが2GB - 1を超えている場合、OCIでは切捨てエラーが発生し、バッファの内容は未定義になります。
次のコード例は、3つのJDBCドライバ(データベース内のOCI、Thinおよびkprb)のすべてで機能します。
バインド:
非ストリーミング・モードの場合:
... String sql = "insert into print_media@dbs2 (product_id, ad_id, ad_final_text)" + " values (:1, :2, :3)"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setInt( 1, 2 ); pstmt.setInt( 2, 20); pstmt.setString( 3, "Java string" ); int rows = pstmt.executeUpdate(); ...
ストリーミング・モードの場合、前述と同じコードが機能しますが、setString()文は次のいずれかで置き換えられます。
pstmt.setCharacterStream( 3, new LabeledReader(), 1000000 ); pstmt.setAsciiStream( 3, new LabeledAsciiInputStream(), 1000000 );
ここで、LabeledReader()およびLabeledAsciiInputStream()により、それぞれ文字ストリームおよびASCIIストリームが生成されます。ad_finaltextがCLOBではなくBLOB列である場合、前述の例は、バインドがRAW型である場合に機能します。
pstmt.setBytes( 3, <some byte[] array> ); pstmt.setBinaryStream( 3, new LabeledInputStream(), 1000000 );
ここで、LabeledInputStream()によってバイナリ・ストリームが生成されます。
定義:
非ストリーミング・モードの場合:
OracleStatement stmt = (OracleStatement)(conn.createStatement());
stmt.defineColumnType( 1, Types.VARCHAR );
ResultSet rst = stmt.executeQuery("select ad_finaltext from print_media@dbs2" );
while( rst.next() )
{
String s = rst.getString( 1 );
System.out.println( s );
}
ストリーミング・モードの場合:
OracleStatement stmt = (OracleStatement)(conn.createStatement());
stmt.defineColumnType( 1, Types.LONGVARCHAR );
ResultSet rst = stmt.executeQuery("select ad_finaltext from print_media@dbs2" );
while( rst.next() )
{
Reader reader = rst.getCharacterStream( 1 );
while( reader.ready() )
{
System.out.print( (char)(reader.next()) );
}
System.out.println();
}
ad_finaltextがCLOBではなくBLOB列である場合、前述の例は、定義がLONGVARBINARY型である場合に機能します。
...
OracleStatement stmt = (OracleStatement)conn.createStatement();
stmt.defineColumnType( 1, Types.INTEGER );
stmt.defineColumnType( 2, Types.LONGVARBINARY );
ResultSet rset = stmt.executeQuery("SELECT ID, LOBCOL FROM LOBTAB@MYSELF");
while(rset.next())
{
/* using getBytes() */
/*
byte[] b = rset.getBytes("LOBCOL");
System.out.println("ID: " + rset.getInt("ID") + " length: " + b.length);
*/
/* using getBinaryStream() */
InputStream byte_stream = rset.getBinaryStream("LOBCOL");
byte [] b = new byte [100000];
int b_len = byte_stream.read(b);
System.out.println("ID: " + rset.getInt("ID") + " length: " + b_len);
byte_stream.close();
}
...
|
関連項目: 『Oracle Database JDBC開発者ガイドおよびリファレンス』の「LOBとBFILEの操作」、CLOBデータを挿入および取得するためのショートカットに関する項 |