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

永続LOBロケータをリモート表からローカル変数に選択できます。これは、PL/SQL、JDBCまたはOCIなどのプログラム・インタフェースで実行できます。リモート列の型にはBLOBCLOBまたは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; 

関連項目:

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

この項では、問合せおよびDML文のバインド値について説明します。

バインド値でクエリおよびDML (INSERTUPDATEDELETE)を使用する場合は、次の4つのケースが考えられます。最初のケースにはローカルの表およびロケータが含まれ、標準の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);

ほとんどの組込み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;

ノート:

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

10.3.2 リモート・ロケータの使用

この項では、PL/SQLおよびOCILOB APIでのリモート・ロケータの使用例を示します。

リモート・ロケータは、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;

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;
/

ほとんどのOCILOB APIでは、リモートLOBロケータに対する操作がサポートされています。次のOCILOB関数のリストは、リモートLOBロケータが渡されるとエラーを返します。

  • 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プログラマーズ・ガイド』を参照してください。

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

ほとんどのOCILOB APIでは、リモートLOBロケータに対する操作がサポートされています。次のOCILOB関数のリストは、リモートLOBロケータが渡されるとエラーを返します。

  • 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プログラマーズ・ガイド』を参照してください。

10.3.4 リモート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など)のロケータと別のデータベース(DB2など)のロケータをバインド変数として使用することはできません。

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

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

  • 2つのロケータを受け入れるDBMS_LOBまたはOCILob APIでは、同じデータベース・リンクを介して両方のLOBロケータを取得する必要があります。次の例で指定されている操作はサポートされません
    SELECT ad_sourcetext INTO clob1 FROM print_media@db1 WHERE product_id = 10011;
    SELECT ad_sourcetext INTO clob2 FROM print_media@db2 WHERE product_id = 10011;
    DBMS_LOB.COPY(clob1, clob2, length(clob2));
  • バインド値は列のLOB型と同じLOB型であることが必要です。たとえば、NCLOBロケータをNCLOB列にバインドし、CLOBロケータをCLOB列にバインドする必要があります。NCLOB型とCLOB型間の暗黙の変換はリモートLOBではサポートされません。

  • 配列バインドを使用するDML文は、バインド操作にリモート・ロケータが含まれる場合、または関連する表がリモート表の場合はサポートされません。

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