永続LOB用のデータ・インタフェースには、LOBデータ型を処理するように拡張された一連のJava API、PL/SQL APIおよびOCI APIが組み込まれています。
これらのAPIは、当初はLONG
、LONG
RAW
およびVARCHAR2
などのレガシー・データ型用に設計されましたが、表20-1と表20-2に示す対応するLOBデータ型にも使用できます。この2つの表で、「バインド型または定義型」列はレガシー・データ型を示し、「LOB列の型」列は対応するサポート対象のLOBデータ型を示します。LOB用のデータ・インタフェースを使用すると、対応するレガシー・データ型に格納されている場合と同様に、文字データとバイナリ・データをLOB列に格納して操作できます。
注意:
データ・インタフェースは、オブジェクトの属性であるLOBのみでなくLOB列に対しても機能します。この章では、「LOB列」とはLOB列およびLOB属性を意味します。
配列のバインドおよび定義インタフェースを使用すると、複数の行を1回のラウンドトリップで挿入および選択できます。
ここでの説明の大半は文字データ型に対象を絞っていますが、同じ概念は表20-1と表20-2に示した完全セットの文字やバイナリ・データ型にも適用されます。これらの表では、CLOB
はNCLOB
も意味しています。
表20-1 SQLとPL/SQLで対応するLONGおよびLOBデータ型
バインド型または定義型 | LOB列の型 | 格納するデータ |
---|---|---|
|
|
文字データ |
|
|
文字データ |
|
|
文字データ |
|
|
バイナリ・データ |
|
|
バイナリ・データ |
表20-2 OCIで対応するLONGおよびLOBデータ型
バインド型または定義型 | LOB列の型 | 格納するデータ |
---|---|---|
|
|
文字データ |
|
|
文字データ |
|
|
文字データ |
|
|
文字データ |
|
|
バイナリ・データ |
|
|
バイナリ・データ |
|
|
バイナリ・データ |
永続LOB用のデータ・インタフェースを使用すると、次のメリットがあります。
アプリケーションでLONG
データ型を使用する場合は、既存のアプリケーションへの変更をまったく、またはほとんど必要とせずにLOBデータ型で同じアプリケーションを使用できます。そのためには、「LONGからLOBへの列の移行」で説明しているように、単に表のLONG
オーディオテープ列をLOBオーディオテープ列に変換します。
逐次アクセス技法を使用するOCIアプリケーションの場合は、パフォーマンスが向上します。データ・インタフェースを使用してピース単位のINSERT
またはフェッチを実行すると、OCILobRead2()
やOCILobWrite2()
などのOCI関数を使用する場合と同様のパフォーマンスが得られます。データ・インタフェースを使用すると、1回のOCIコールでLOBに4KBを超えるデータを挿入できるため、サーバーへのラウンドトリップを削減できます。
最初にLOBロケータをフェッチしてからOCILobRead2()
をコールするかわりに、1回のOCIStmtFetch()
コールでLOBデータを読み取ることができます。これにより、LOBデータを最初から読み取る場合のパフォーマンスが向上します。
配列のバインドおよび定義インタフェースを使用すると、LOBを含む複数の行を1回のラウンドトリップで挿入および選択できます。
このデータ・インタフェースを使用すると、表20-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データより短い場合は、データベースで例外が発生します。
関連項目:
SQL文でのLOBサポートの詳細は、「SQLセマンティクスとLOB」を参照してください
この項では、永続LOB用のデータ・インタフェースを使用してLOB列またはLOB属性にアクセスする方法について説明します。
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列の場合は、暗黙的な割当てとパラメータの受渡しがサポートされます。
表20-1および表20-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ユーザーは、アプリケーションで若干のパフォーマンス低下を感じます。
暗黙的なパラメータの受渡しは、文字データを受け入れる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
型に変換できることにも注意してください。
PL/SQLまたはCのプロシージャをPL/SQLからコールできます。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'));
次の文は2000バイトしか挿入しません。LPAD
の結果は4000バイトに制限されており、16進からRAWへ暗黙的に変換すると、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列にバインドできません。
SecureFiles LOBまたはBasicFiles LOBがあるパーティション表と、SecureFiles LOBのみの非パーティション表に対して実行するとき、Oracleは次の大部分のDML操作のパラレル実行をサポートしています。
INSERT
INSERT AS SELECT
CREATETABLEASSELECT
DELETE
UPDATE
MERGE
(条件付きUPDATE
およびINSERT
)
複数表INSERT
SQL*Loader
インポート/エクスポート
リリース12c以降では、パラレルDMLのサポート強化に次の点が含まれています。
非パーティション表でSecureFiles LOBとして格納されるLOB列。(以前のリリースに、パーティション表はすでに含まれている)
コンテキスト索引が定義されているSecureFiles LOB列の直接ロードのサポート。
制限事項
表にSecureFiles LOBのみでなく、BasicFiles LOB列も含まれている場合、パラメータ挿入ダイレクト・ロード(PIDL)は無効です。
ドメイン索引の一部の実装では負荷分散が制限され、設計上パフォーマンスが損われる可能性があります。
トップレベルへの非パーティション表には、並列度を指定する必要があります。
関連項目:
『Oracle Database管理者ガイド』のパラレルSQL実行プロセスの管理に関する項を参照してください。
次の例では、INSERT
およびUPDATE
操作で4000バイトを超えるバインドの使用例を示します。
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 retrieves the LOB column if it is up to 100 bytes, otherwise it * raises 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 raises 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関数は表20-2に示すLONG
データ型とLOBデータ型を受け入れます。
OCIBindByName()
およびOCIBindByPos()
これらの関数を使用して、INSERT
操作およびUPDATE
操作用にSQL文またはPL/SQLブロック内のプログラム変数とプレースホルダ間の対応付けを行います。
OCIBindDynamic()
このコールを使用して、INSERT
操作またはUPDATE
操作用に動的にデータを割り当てるためのコールバックを登録します。
OCIStmtGetPieceInfo()
およびOCIStmtSetPieceInfo()
これらのコールを使用して、ピース単位操作のためのピース情報を取得または設定します。
永続LOB用のデータ・インタフェースを使用すると、次のOCI関数で表20-2に示すLONGデータ型とLOBデータ型を受け入れることができます。
OCIDefineByPos()
このコールを使用して、SELECT
リストにある項目を型および出力データ・バッファに対応付けます。
OCIDefineDynamic()
このコールを使用して、OCIDefineByPos()
関数のコールでOCI_DYNAMIC_FETCH
モードが選択された場合、SELECT
操作に対してユーザー・コールバックを登録します。
これらの関数をLOB型に使用すると、LOBロケータではなくLOBデータがバッファに選択されます。OCIでは、LOB用のデータ・インタフェースを使用して読み取る量を指定できないことに注意してください。指定できるのは、バッファ長のみです。バッファに収まる量のデータのみが読み取られ、データが切り捨てられます。
クライアントのキャラクタ・セットがマルチバイト形式の場合、データ・インタフェースに組み込まれている関数は、次のように、LONGデータ型の場合と同様にLOBデータ型を操作します。
マルチバイト・キャラクタ・セットでのピース単位フェッチの場合、マルチバイト文字が途中で切れることがあり、一部のバイトが1つのバッファの最後に、残りのバイトが次のバッファに入ることがあります。
通常のフェッチの場合、最後の文字のバイトの一部をバッファで保持できない場合には、バッファに収まるかぎりのバイトが戻されるため、部分的な文字にしかなりません。
この項では、データ・インタフェースを使用してLOB列またはLOB属性のINSERT
操作またはUPDATE
操作を実行する各種の方法について説明します。この項で説明する操作は、OCI環境を初期化して必要なハンドルをすべて割当て済であることを前提としています。
永続LOB用のデータ・インタフェースを使用して、1つのピースで単純なINSERT
操作またはUPDATE
操作を実行する手順は、次のとおりです。
OCIStmtPrepare()
をOCI_DEFAULT
モードでコールして、文を準備します。OCIBindByName()
またはOCIBindbyPos()
をOCI_DEFAULT
モードでコールして、LOBを文字データまたはバイナリ・データとしてバインドするためにプレースホルダをバインドします。 OCIStmtExecute()
をコールして、実際のINSERT
操作またはUPDATE
操作を実行します。 永続LOB用のデータ・インタフェースを使用して、ポーリングによりピース単位のINSERT
操作またはUPDATE
操作を実行する手順は、次のとおりです。
永続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
モードでコールして、文を準備します。OCIDefinebyPos()
をOCI_DYNAMIC_FETCH
モードでコールして、LOB列を文字データまたはバイナリ・データとして定義するために、選択リストの位置を定義します。OCIStmtExecute()
をコールしてSELECT
文を実行します。OCIDefineDynamic()
をコールしてコールバックを指定します。OCIStmtFetch()
をデフォルト・モードでコールします。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;
INSERT
およびUPDATE
操作では、4000バイトを超えるバインドを使用できます。
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をコールするプログラムでは、次のような場合が考えられます。
begin foo(:1); end;形式でのPL/SQLアウトバインドのコール
次に例を示します。
text *sqlstmt = (text *)"BEGIN PKG1.P5 (:c); END; " ;
call foo(:1);形式でのPL/SQLアウトバインドのコール
次に例を示します。
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を作成します。データの長さが不明である場合は、プロジェクトを向上させるために、長さパラメータを受け入れるsetBinaryStream()またはsetCharacterStreamファンクションのバージョンを使用します。これら両方の技法によってデータベースのラウンドトリップが削減され、場合によってはパフォーマンスが向上します。適用される大幅な制限については、http://www.oracle.com/technology/
でストリーム・データに関するJavadocを参照してください。
『Oracle JDBC開発者ガイドおよびリファレンス』で、次の内容を参照してください。
関連項目:
『Oracle Database JDBC開発者ガイド』の「LOBとBFILEの操作」、LOB用のデータ・インタフェースに関する項
『Oracle Database JDBC開発者ガイド』の「JDBC標準サポート」
リモートLOBの挿入、更新および選択を行うためのデータ・インタフェース(dblink
を介したアクセス)は、Oracle Database 10gリリース2以上でサポートされています。
説明する例では、dbs1
とdbs2
という2つのスキーマ内に作成された表print_media
を使用しています。例で使用されている表のCLOB
列は、ad_finaltext
です。次の項に示すPL/SQL、OCIおよびJavaについての例では、この1つの列に対してバインドおよび定義を使用していますが、複数の列にアクセスすることも可能です。次に、サポートされている機能とその制限を示します。
CLOB
をCHAR
またはNCHAR
として、NCLOB
をCHARまたはNCHARとして定義できます。CLOB
およびNCLOB
は、LONG
として定義できます。BLOB
は、RAW
またはLONG
RAW
として定義できます。
配列のバインドおよび定義はサポートされています。
関連項目:
「PL/SQLにおけるリモート・データ・インタフェースの例」およびその次の項。
特定の構文はリモートLOBではサポートされていません。
複数のデータベースを使用する問合せはサポートされていません。
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開発者ガイド』