5 分散LOB

5.1 リモートLOBの操作

リモート表のLOBデータは次の方法で操作できます。

  • データべース・リンクを使用してアクセスされるリモート表のLOB列(リモートLOB列)を直接参照する。

  • ローカルLOBロケータ変数にリモートLOB列を選択する(リモート・ロケータ)。

内容は次のとおりです。

5.1.1 リモートLOB列の操作

5.1.1.1 AS SELECT形式での表の作成または挿入

次の形式で作成された文の選択リストでは、スタンドアロンのLOB列のみ使用できます。

CREATE TABLE t AS SELECT * FROM table1@remote_site;
INSERT INTO t SELECT * FROM table1@remote_site;
UPDATE t SET lobcol = (SELECT lobcol FROM table1@remote_site);
INSERT INTO table1@remote_site SELECT * FROM local_table;
UPDATE table1@remote_site SET lobcol = (SELECT lobcol FROM local_table);
DELETE FROM table1@remote_site <WHERE clause involving non_lob_columns>
5.1.1.2 スカラーを戻すリモートLOB上のファンクション

LOBパラメータを含み、スカラー・データ型を戻すSQLおよびPL/SQLファンクションがサポートされています。他のSQLファンクションとDBMS_LOB APIの場合、リモートのLOB列に対する使用はサポートされていません。たとえば、次の文はサポートされています。

CREATE TABLE tab AS SELECT DBMS_LOB.GETLENGTH@dbs2(clob_col) len FROM tab@dbs2;
CREATE TABLE tab AS SELECT LENGTH(clob_col) len FROM tab@dbs2;

ただし、次の文は、DBMS_LOB.SUBSTRがLOBを戻すため、サポートされていません。

CREATE TABLE tab AS SELECT DBMS_LOB.SUBSTR(clob_col) from tab@dbs2; 
5.1.1.3 リモートLOB用のデータ・インタフェース

文字またはバイナリのバッファをリモートのCLOBまたはBLOBに挿入、およびリモートのCLOBまたはBLOBを選択して、(PL/SQLを使用するなどで)文字またはバイナリのバッファに挿入できます。

SELECT clobcol1, type1.blobattr INTO varchar_buf1, raw_buf2 FROM table1@remote_site;
INSERT INTO table1@remotesite (clobcol1, type1.blobattr) VALUES varchar_buf1, raw_buf2;
INSERT INTO table1@remotesite (lobcol) VALUES ('test');
UPDATE table1 SET lobcol = 'xxx';

5.1.2 リモート・ロケータの操作

ローカル変数にリモート表からの永続LOBロケータを選択できます。これはPL/SQLまたはOCIで実行できます。リモート列の型にはBLOB、CLOBまたはNCLOBのいずれかを指定できます。この章のリモートLOBロケータのすべての例は次のSQL文が基礎となっています。

CREATE TABLE lob_tab (c1 NUMBER, c2 CLOB);

次の例では、リモート・データベースで定義されている表lob_tab (CLOB型の列c2とnumber型のc1を使用)に、データベース・リンクdb2とローカルのCLOB変数lob_var1を使用してアクセスできます。

SELECT c2 INTO lob_var1 FROM lob_tab@db2 WHERE c1=1;
SELECT c2 INTO lob_var1 FROM lob_tab@db2 WHERE c1=1 for update;

PL/SQLでは、ファンクションdbms_lob.isremoteを使用して特定のLOBがリモート表に属しているかどうかを確認できます。同様に、OCIでは、OCILobLocatorOCI_ATTR_LOB_REMOTE属性を使用して特定のLOBがリモート表に属しているかどうか確認できます。次に例を示します。

IF(dbms_lob.isremote(lob_var1)) THEN
dbms_output.put_line(‘LOB locator is remote)
ENDIF; 

関連項目:

内容は次のとおりです。

5.1.2.1 リモート表での問合せとDMLを使用したバインドとしてのローカル・ロケータおよびリモート・ロケータの使用

バインド値でクエリおよびDML (INSERTUPDATEDELETE)を使用する場合は、次の4つのケースが考えられます。1つ目は、ローカルの表とロケータを必要とする、標準のLOB機能です。他の3つは分散LOB機能で、このセクションの終わりにリストされている制限があります。

  • バインド値としてローカル・ロケータを使用するローカル表。

  • バインド値としてリモート・ロケータを使用するローカル表

  • バインド値としてローカル・ロケータを使用するリモート表

  • バインド値としてリモート・ロケータを使用するリモート表

リモートLOBロケータを使用する次のような形の問合せはサポートされません。

SELECT name FROM lob_tab@db2 WHERE length(c1)=length(:lob_v1);

前述の問合せでは、c1はLOB列、lob_v1がリモート・ロケータになります。

リモートLOBロケータを使用する次のような形のDMLはサポートされます。ここで、バインド値にはローカルまたはリモートの永続LOBロケータを指定できます。

UPDATE lob_tab@db2 SET c1=:lob_v1;

INSERT into lob_tab@db2 VALUES (:1, :2);

ノート:

returning句を含むDMLは、スカラーおよびLOB両方の列についてリモート表でサポートされません。
5.1.2.2 リモートLOBロケータ使用時の制限

リモートLOBロケータ使用時の一般的な制限は次のとおりです。

  • SELECT文を使用してローカル変数にリモートの一時LOBロケータを選択することはできません。次に例を示します。

    select substr(c2, 3, 1) from lob_tab@db2 where c1=1

    前述の問合せはエラーを返します。

  • リモートLOB機能は、索引構成表(IOT)ではサポートされません。リモートからロケータを取得しようとすると、IOT表でエラーが発生します。

  • ローカル・データベースとリモート・データベースのいずれもデータベース12.2以上のバージョンであることが必要です。

  • 分散LOB機能では、from句またはwhere句に指定されている表は同じデータベースで収集する必要があります。リモート・ロケータをwhere句のバインド変数として使用する場合、これらのロケータは同じリモート・データベースに属している必要があります。DB1のロケータを1つとDB2の別のロケータをバインド変数として使用できません。

  • 収集した表またはロケータでは同じデータベース・リンクが使用されます。同じデータベースをポイントする2つの異なるDBリンクを使用できます。次の例では、dblink1dblink2の両方が同じリモート・データベースをポイントしていますが、認証方法が異なっている可能性があります。Oracle Databaseはこのような操作をサポートしません。

    INSERT into tab1@dblink1 SELECT * from tab2@dblink2;

  • バインド値は列のLOB型と同じLOB型であることが必要です。たとえば、NCLOBロケータはNCLOB列にバインドされ、CLOBロケータはCLOB列にバインドされる必要があります。NCLOB型とCLOB型間の暗黙の変換はリモートLOBではサポートされません。

  • 配列バインドでのDML (INSERT/UPDATE)は、バインドにリモート・ロケータが必要な場合や関連する表にリモート表である場合はサポートされません。

  • ローカル変数にリモート表からのBFILE列は選択できません。

5.2 リモート表のLOBでのSQLセマンティクス

内容は次のとおりです。

5.2.1 リモートLOBおよびBFILE用の組込みファンクション

ネストしたファンクションによって戻される最終値がLOB型でないかぎり、ローカルのLOBとBFILEでサポートされるすべてのSQL組込みファンクションおよびユーザー定義型ファンクションは、リモートのLOBとBFILEでもサポートされます。これには、リモートの永続および一時LOBとBFILE用のファンクションも含まれます。

リモート・サイトで実行されるSQL組込みファンクションは、SELECTINSERTUPDATEおよびDELETEと同様に、SQL文内に含めることができます。次に例を示します。

SELECT LENGTH(ad_sourcetext) FROM print_media@remote_site -- CLOB
SELECT LENGTH(ad_fltextn) FROM print_media@remote_site;   -- NCLOB
SELECT LENGTH(ad_composite) FROM print_media@remote_site; -- BLOB
SELECT product_id from print_media@remote_site WHERE LENGTH(ad_sourcetext) > 3;

UPDATE print_media@remote_site SET product_id = 2 WHERE LENGTH(ad_sourcetext) > 3;

SELECT TO_CHAR(foo@dbs2(...)) FROM dual@dbs2;
-- where foo@dbs2 returns a temporary LOB

SQLファンクションは、次のカテゴリに分類されます(ただし、必ずしもこれに限定されません)。

  • LOBでサポートされていないSQLファンクションは次のとおりです。

    これらの関数は、CLOBにのみ関連します。たとえばDECODEなどです。

    これらのファンクションは、ローカルのLOBでサポートされないため、リモートのLOBではサポートされません

  • 1つのLOB引数のみ(その他の引数は他のデータ型)を受け入れ、LOBを戻さないファンクション:

    これらのファンクションは、CLOB、NCLOBおよびBLOBのみに該当します。たとえばLENGTHが該当し、これはサポートされています。次に例を示します。

    SELECT LENGTH(ad_composite) FROM print_media@remote_site;
    SELECT LENGTH(ad_header.logo) FROM print_media@remote_site; -- LOB in object
    SELECT product_id from print_media@remote_site WHERE LENGTH(ad_sourcetext) > 3;
    
  • LOBを戻すファンクション:

    これらのファンクションは、すべてCLOBおよびNCLOBのみに該当します。これらのファンクションは、元のLOBを戻すか、または一時LOBを生成する場合があります。これらのファンクションは、ローカル・サイトに戻される結果がLOBでないかぎり、リモート・サイトで実行できます。

    一時LOBを戻すファンクションには、REPLACESUBSTRCONCAT、||、TRIMLTRIMRTRIMLOWERUPPERNLS_LOWERNLS_UPPERLPAD、およびRPADがあります。

    元のLOBロケータを戻すファンクションには、NVLDECODEおよびCASEがあります。現在、DECODEおよびCASEではLOBの操作はサポートされていませんが、他のデータ型を操作でき、LOBを戻すことができます。

    たとえば、次の文がサポートされています。

    SELECT TO_CHAR(CONCAT(ad_sourcetext, ad_sourcetext)) FROM print_media@remote_site;
    SELECT TO_CHAR(SUBSTR(ad_fltextnfs, 1, 3)) FROM print_media@remote_site;
    

    しかし、次の文はサポートされていません。

    SELECT CONCAT(ad_sourcetext, ad_sourcetext) FROM print_media@remote_site;
    SELECT SUBSTR(ad_sourcetext, 1, 3) FROM print_media@remote_site;
    
  • 1つ以上のLOB引数を受け入れるファンクション。

    これらには、INSTRLIKEREPLACECONCAT、||、SUBSTRTRIMLTRIMRTRIMLPADおよびRPADがあります。これらのファンクションは、すべてCLOBおよびNCLOBのみに該当します。

    すべてのLOBが同じdblink内にあり、戻される値がLOBでない場合にのみ、これらのファンクションがサポートされます。たとえば、次がサポートされています。

    SELECT TO_CHAR(CONCAT(ad_sourcetext, ad_sourcetext)) FROM print_media@remote_site; -- CLOB
    SELECT TO_CHAR(CONCAT(ad_fltextn, ad_fltextn)) FROM print_media@remote_site; -- NCLOB
    

    しかし、次はサポートされていません。

    SELECT TO_CHAR(CONCAT(a.ad_sourcetext, b.ad_sourcetext)) FROM print_media@db1 a, print_media@db2 b WHERE a.product_id = b.product_id;
    

5.2.2 組込みSQLファンクションへのリモート・ロケータの受け渡し

ほとんどの組込みSQLファンクション(LENGTH、INSTR、SUBSTRUPPERなど)にリモート・ロケータを渡すことができます。次に例を示します。
Var lob1 CLOB;
BEGIN
	select c2 into lob1 from lob_tab@db2 where c1=1;
END;
/
select length(:lob1) from dual;

5.3 PL/SQLでのリモートLOBの操作

内容は次のとおりです。

5.3.1 リモートLOBおよびBFILE用のPL/SQLファンクション

ネストしたファンクションによって戻される最終値がLOBでないかぎり、リモート・サイトで実行され、リモートLOBとBFILEを操作する、組込みおよびユーザー定義型PL/SQLファンクションを使用できます。

次の例では、LOBの例の表: PMスキーマのprint_media表で説明されているprint_media表を使用します

SELECT product_id FROM print_media@dbs2 WHERE foo@dbs2(ad_sourcetext, 'aa') > 0;
-- foo is a user-define function returning a NUMBER

DELETE FROM print_media@dbs2 WHERE DBMS_LOB.GETLENGTH@dbs2(ad_graphic) = 0;
5.3.1.1 リモートのユーザー定義型ファンクションの制限
  • SQLファンクションに適用される制限はここにも適用されます。

  • 1つのdblink内のファンクションは、他のdblink内のLOBデータを操作できません。たとえば、次の文はサポートされていません。

    SELECT a.product_id FROM print_media@dbs1 a, print_media@dbs2 b WHERE 
       CONTAINS@dbs1(b.ad_sourcetext, 'aa') > 0;
    
  • 1つの問合せブロックに、異なるdblinkの表およびファンクションを含めることはできません。たとえば、次の文はサポートされていません。

    SELECT a.product_id FROM print_media@dbs2 a, print_media@dbs3 b
        WHERE CONTAINS@dbs2(a.ad_sourcetext, 'aa') > 0 AND
        foo@dbs3(b.ad_sourcetext) > 0;
    --  foo is a user-defined function in dbs3
    
  • PL/SQLからのSQL文の発行以外、PL/SQL内からのリモートLOB操作の実行(DBMS_LOB)はサポートされていません。

5.3.1.2 PL/SQL、OCIおよびJDBC内のリモート・ファンクション

「リモートのユーザー定義型ファンクションの制限」にリストされているすべてのSQL文は、PL/SQL、OCI、JDBC内から実行された場合、同じように機能します。追加機能はありません。

5.3.2 PL/SQLでのリモート・ロケータの使用

リモート・ロケータは、LOBを入力として受け付ける、LENGTHINSTRSUBSTRUPPERなどの組込みPL/SQLファンクションとして渡すことができます。次に例を示します。
DECLARE 
substr_data varchar2(4000); 
remote_loc CLOB; 
BEGIN 
SELECT c2 into remote_loc 
FROM lob_tab@db2 WHERE c1=1; 
substr_data := substr(remote_loc, position, length) 
END;

5.3.3 DBMS_LOBでのリモート・ロケータの使用

BFILEを対象としたAPIを除くすべてのDBMS_LOB APIは、リモートLOBロケータでの操作をサポートします。

次の例は、dbms_lob操作の入力としてリモート・ロケータを渡す方法を示しています。

DECLARE
  lob CLOB;
  buf VARCHAR2(120) := 'TST';
  amt NUMBER(2);
  len NUMBER(2);
BEGIN
  amt :=30;
  select c2 into lob from lob_tab@db2 where c1=3 for update;
  dbms_lob.write(lob, amt, 1, buf);
  amt :=30;
  dbms_lob.read(lob, amt, 1, buf);
  len := dbms_lob.getlength(lob);
  dbms_output.put_line(buf);
  dbms_output.put_line(amt);
  dbms_output.put_line('get length output = ' || len);
END;
/

内容は次のとおりです。

5.3.3.1 DBMS_LOBでのリモート・ロケータの使用に関する制限

2つのLOBロケータを受け付けるすべてのAPIでは、両方のLOBを1つのデータベースで収集する必要があります。

関連項目:

5.4 OCILOB APIでのリモート・ロケータの使用

(BFILEを対象としたAPIを除く)すべてのOCILOB APIは、リモートLOBでの操作をサポートします。

ノート:

2つのロケータを受け付けるすべてのAPIは、両方のLOBロケータを同じデータベース・リンクから取得する必要があります。

次のOCILOBファンクションのリストには、リモートLOBロケータがそれらのファンクションに渡された場合にエラーが示されます。

  • OCILobAssign

  • OCILobLocatorAssign

  • OCILobArrayRead()

  • OCILobArrayWrite()

  • OCILobLoadFromFile2()

次の例は、リモート・ロケータをOCILOB APIに渡す方法を示しています。

void select_read_remote_lob()
{
  text *select_sql = (text *)"SELECT c2 lob_tab@dbs1 where c1=1";
  ub4 amtp = 10;
  ub4 nbytes = 0;
  ub4 loblen=0;
  OCILobLocator * one_lob;
  text strbuf[40];

 /* initialize single locator */
 OCIDescriptorAlloc(envhp, (dvoid **) &one_lob,
                 (ub4) OCI_DTYPE_LOB,
                 (size_t) 0, (dvoid **) 0)

 OCIStmtPrepare(stmthp, errhp, select_sql, (ub4)strlen((char*)select_sql),
                 (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT);

 OCIDefineByPos(stmthp, &defp, errhp, (ub4) 1,
                     (dvoid *) &one_lob,
                     (sb4) -1,
                     (ub2) SQLT_CLOB,
                     (dvoid *) 0, (ub2 *) 0,
                     (ub2 *) 0, (ub4) OCI_DEFAULT));

 /* fetch the remote locator into the local variable one_lob */
 OCIStmtExecute(svchp, stmthp, errhp, 1, 0, (OCISnapshot *)0, 
                 (OCISnapshot *)0, OCI_DEFAULT);

 /* Get the length of the remote LOB */
 OCILobGetLength(svchp, errhp,
                (OCILobLocator *) one_lob, (ub4 *)&loblen)

 printf("LOB length = %d\n", loblen);

 memset((void*)strbuf, (int)'\0', (size_t)40);

 / * Read the data from the remote LOB */
 OCILobRead(svchp, errhp, one_lob, &amtp,
                (ub4) 1, (dvoid *) strbuf, (ub4)& nbytes, (dvoid *)0,
                (OCICallbackLobRead) 0,
                (ub2) 0, (ub1) SQLCS_IMPLICIT));
 printf("LOB content = %s\n", strbuf);

}

関連項目:

OCILOB APIの完全なリストについては、『OCIプログラマーズ・ガイド』を参照してください。