10.2 リモートLOBでのデータ・インタフェースの使用

データ・インタフェースを使用すると、CLOB列に対してCHARACTERバッファをバインドおよび定義し、BLOB列に対してRAWバッファをバインドおよび定義できます。このインタフェースは、リモートLOB列でもサポートされます。

LOBロケータを使用するよりもデータ・インタフェースを使用する利点は、LOBデータをフェッチするためにリモート・サーバーへのラウンドトリップを1回のみ行うことです。配列のバインドまたは定義の一部として使用する場合、配列操作全体に対して1回のラウンドトリップのみが使用されます。

このマニュアルで説明されている例では、dbs1スキーマとdbs2スキーマで作成されたprint_media表を使用します。例で使用されているprint_media表のCLOB列は、ad_finaltextです。次の各項のPL/SQL、OCIおよびJavaの例では、この列のバインドおよび定義を使用していますが、複数の列にアクセスすることもできます。サポートされる機能は次のとおりです。

  • CLOBVARCHAR2として、BLOBRAWとしてバインドおよび定義できます。
  • 配列のバインドおよび定義はサポートされています。

この項では、PL/SQLでLOBとリモート・データ・インタフェースを使用する方法について説明します。

PL/SQLにおけるデータ・インタフェースでは、サイズが32KB未満のデータのみがサポートされています。次にPL/SQLの例を示します。

CONNECT pm/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_finaltextCLOBではなくBLOB列である場合、my_adRAW型である必要があります。LOBのサイズが32KB - 1を超えている場合、PL/SQLでは切捨てエラーが発生し、バッファの内容は未定義になります。

この項では、JDBCでLOBと一緒にリモート・データ・インタフェースを使用する方法を示します。

次のコード・スニペットは、すべてのJDBCドライバで機能します。

バインド:

非ストリーミング・モードの場合:

...
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();
...

ノート: Oracleでは、最大2GBのサイズの文字列に対して非ストリーミング・モードがサポートされます。ただし、コンピュータのメモリー・サイズが制限要因になる場合があります。

ストリーミング・モードの場合、前述と同じコードが機能しますが、setString()文は次のいずれかで置き換えられます。

pstmt.setCharacterStream( 3, new LabeledReader(), 1000000 );
pstmt.setAsciiStream( 3, new LabeledAsciiInputStream(), 1000000 );

ノート: ストリーミング・インタフェースを使用して、ギガバイト・サイズの文字およびバイナリ・データをLOB列に挿入できます。

ここで、LabeledReader()およびLabeledAsciiInputStream()により、それぞれ文字ストリームおよびASCIIストリームが生成されます。ad_finaltextCLOBではなく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 );
     }

ノート: LOBサイズが32767バイトより大きい場合、データは切り捨てられ、エラーはスローされません。

ストリーミング・モードの場合:

OracleStatement stmt = (OracleStatement)(conn.createStatement());
  stmt.defineColumnType( 1, Types.LONGVARCHAR );
  ResultSet rs = stmt.executeQuery("select ad_finaltext from print_media@dbs2" );
  while(rs.next()) {  
    Reader reader = rs.getCharacterStream( 1 );  
    int data = 0;  
    data = reader.read();   
    while( -1 != data ){    
      System.out.print( (char)(data) );    
      data = reader.read();  
    }  
    reader.close();
  }

ノート: データ型をLONGVARCHARとして指定すると、LOB全体を選択できます。定義タイプがLONGVARCHARではなくVARCHARに設定されている場合、データは32kで切り捨てられます。

ad_finaltextCLOBではなく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();
    }
...

この項では、OCIでLOBと一緒にリモート・データ・インタフェースを使用する方法を示します。

OCIにおけるデータ・インタフェースでは、サイズが2 GB未満(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(...);
...

BLOB列には、SQLT_BIN型を使用する必要があります。たとえば、ad_finaltext列をCLOB列ではなくBLOB列として定義する場合、SQLT_BIN型を使用して列データをバインドおよび定義する必要があります。LOBのサイズが2GB - 1バイトを超えている場合、OCIでは切捨てエラーが発生し、バッファの内容は未定義になります。

この項では、リモートLOBでのデータ・インタフェースの使用に関する制限事項について説明します。

特定の構文はリモート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では、CHARCLOBの間の暗黙的な変換はサポートされていません。

  • 実引数がLOB型であり、リモート引数がVARCHAR2NVARCHAR2CHARNCHARまたはRAWである場合、PL/SQLパラメータの受渡しは許可されません。

10.2.1 PL/SQLにおけるリモート・データ・インタフェースの例

この項では、PL/SQLでLOBとリモート・データ・インタフェースを使用する方法について説明します。

PL/SQLにおけるデータ・インタフェースでは、サイズが32KB未満のデータのみがサポートされています。次にPL/SQLの例を示します。

CONNECT pm/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_finaltextCLOBではなくBLOB列である場合、my_adRAW型である必要があります。LOBのサイズが32KB - 1を超えている場合、PL/SQLでは切捨てエラーが発生し、バッファの内容は未定義になります。

10.2.2 JDBCにおけるリモート・データ・インタフェースの例

この項では、JDBCでLOBと一緒にリモート・データ・インタフェースを使用する方法を示します。

次のコード・スニペットは、すべてのJDBCドライバで機能します。

バインド:

非ストリーミング・モードの場合:

...
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();
...

ノート:

Oracleでは、最大2 GBのサイズの文字列に対して非ストリーミング・モードがサポートされます。ただし、コンピュータのメモリー・サイズが制限要因になる場合があります。

ストリーミング・モードの場合、前述と同じコードが機能しますが、setString()文は次のいずれかで置き換えられます。

pstmt.setCharacterStream( 3, new LabeledReader(), 1000000 );
pstmt.setAsciiStream( 3, new LabeledAsciiInputStream(), 1000000 );

ノート:

ストリーミング・インタフェースを使用して、ギガバイト・サイズの文字およびバイナリ・データをLOB列に挿入できます。

ここで、LabeledReader()およびLabeledAsciiInputStream()により、それぞれ文字ストリームおよびASCIIストリームが生成されます。ad_finaltextCLOBではなく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 );
     }

ノート:

LOBサイズが32767バイトより大きい場合、データは切り捨てられ、エラーはスローされません。

ストリーミング・モードの場合:

OracleStatement stmt = (OracleStatement)(conn.createStatement());
  stmt.defineColumnType( 1, Types.LONGVARCHAR );
  ResultSet rs = stmt.executeQuery("select ad_finaltext from print_media@dbs2" );
  while(rs.next()) {  
    Reader reader = rs.getCharacterStream( 1 );  
    int data = 0;  
    data = reader.read();   
    while( -1 != data ){    
      System.out.print( (char)(data) );    
      data = reader.read();  
    }  
    reader.close();
  }

ノート:

データ型をLONGVARCHARとして指定すると、LOB全体を選択できます。定義タイプがLONGVARCHARではなくVARCHARに設定されている場合、データは32kで切り捨てられます。

ad_finaltextCLOBではなく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();
    }
...

10.2.3 OCIにおけるリモート・データ・インタフェースの例

この項では、OCIでLOBと一緒にリモート・データ・インタフェースを使用する方法を示します。

OCIにおけるデータ・インタフェースでは、サイズが2 GB未満(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(...);
...

BLOB列には、SQLT_BIN型を使用する必要があります。たとえば、ad_finaltext列をCLOB列ではなくBLOB列として定義する場合、SQLT_BIN型を使用して列データをバインドおよび定義する必要があります。LOBのサイズが2GB - 1バイトを超えている場合、OCIでは切捨てエラーが発生し、バッファの内容は未定義になります。

10.2.4 リモートLOBでのデータ・インタフェースに関する制限事項

この項では、リモートLOBでのデータ・インタフェースの使用に関する制限事項について説明します。

特定の構文はリモート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;
    
  • RETURNING INTOでは、CHARCLOBの間の暗黙的な変換はサポートされていません。

  • 実引数がLOB型であり、リモート引数がVARCHAR2NVARCHAR2CHARNCHARまたはRAWである場合、PL/SQLパラメータの受渡しは許可されません。