9.2 LOB用のPL/SQL API

DBMS_LOBパッケージを使用すると、PL/SQLのLOBにアクセスして変更を加えられます。

関連項目:

DBMS_LOBパッケージの詳細は、DBMS_LOBを参照してください。

DBMS_LOB操作のオフセット・パラメータおよび量パラメータのガイドライン

DBMS_LOB PL/SQLパッケージ・プロシージャで使用されるoffsetおよびamountパラメータには、次のガイドラインが適用されます。

  • 固定幅または可変幅のいずれかのすべての形式の文字データの場合、amountおよびoffsetパラメータは文字で表されます。これは、CLOBデータ型とNCLOBデータ型に対する操作に適用されます。
  • バイナリ・データの場合、offsetパラメータとamountパラメータはバイト単位です。このガイドラインはBLOBデータ型に対する操作に適用されます。
  • DBMS_LOB.READプロシージャを使用する場合、amountパラメータはバッファのサイズ以下にする必要があります(32Kに制限されます)。ただし、amountパラメータは、LOBデータのサイズより大きくできます。

表9-2 LOB用のDBMS_LOB関数およびプロシージャ

分類 関数およびプロシージャ 説明
健全性チェック ISSECUREFILE BLOBまたはCLOBロケータがSecureFileかどうかを確認
オープンとクローズ OPEN LOBをオープン
ISOPEN LOBがオープンしているかどうかの確認
CLOSE LOBのクローズ
読取り操作 GETLENGTH  
GET_STORAGE_LIMIT  
GETCHUNKSIZE  
READ  
SUBSTR  
INSTR  
変更操作 WRITE 指定されたオフセットからLOBにデータを書き込みます
WRITEAPPEND データをLOBの終わりに書き込みます。
ERASE 指定のオフセットから開始して、LOBの一部を消去します
TRIM LOB値の指定された長さまでの切捨て
複数のロケータを含む操作 COMPARE 2つのLOBの値の全体または一部の比較
APPEND LOB値を別のLOBに追加します
COPY LOBの全体または一部を他のLOBにコピーします。
dst := src LOBロケータsrcのLOBロケータdstへの割当て
CONVERTTOBLOB、CONVERTTOCLOB BLOBCLOBに、またはCLOBBLOBに変換
LOADCLOBFROMFILE,LOADBLOBFROMFILE BFILEデータのLOBへのロード
SecureFilesに固有の操作 GETOPTIONS SecureFilesのオプション(重複除外、圧縮、暗号化)を戻します。
SETOPTIONS SecureFilesのLOB機能(重複除外および圧縮)を設定します
GETCONTENTTYPE SecureFilesのコンテンツ文字列を取得します。
SETCONTENTTYPE SecureFilesのコンテンツ文字列を設定します。
FRAGMENT_DELETE LOBの指定されたオフセットから指定された長さのデータを削除します。
FRAGMENT_INSERT LOBの指定されたオフセットに、指定されたデータ(32KB未満)を挿入します。
FRAGMENT_MOVE 指定されたオフセットから他の指定されたオフセットに、指定されたバイト数を移動します。
FRAGMENT_REPLACE 指定されたオフセットのデータを、指定されたデータ(32KB未満)と置換します。

例9-1 LOB用のPL/SQL API

DECLARE
   retval    INTEGER;
   clob1     CLOB;
   clob2     CLOB;
   clob3     CLOB;
   blob1     BLOB;
   buf       VARCHAR2(32767);
   buflen    INTEGER := 32760;
   loblen1   INTEGER;
     
   -- Following are the variables that you need for the convertToBlob and convertToClob functions
   amt     NUMBER := 0;
   src     NUMBER := 1 ;
   dst     NUMBER := 1 ;
   lang    NUMBER := 0;
   warn    NUMBER;
 
 BEGIN
   SELECT ad_sourcetext INTO clob1 FROM print_media
     WHERE product_id = 1 AND ad_id = 1;

    -- the select statement is defined with FOR UPDATE so that we can write to it
   SELECT ad_finaltext INTO clob2 FROM print_media
     WHERE product_id = 1 AND ad_id =1 FOR UPDATE; 
   /* Note that all the writes to clob2 will get reflected in the column */
 
   /*------------------------------------------------------------------*/
   /*---------------------- Sanity Checking ---------------------------*/
   /*------------------------------------------------------------------*/
   if DBMS_LOB.ISSECUREFILE(clob1) = TRUE then
     DBMS_OUTPUT.PUT_LINE('CLOB1 is SECUREFILE');
   else
     DBMS_OUTPUT.PUT_LINE('CLOB1 is BASICFILE');
   end if;
 
   /*------------------------------------------------------------------*/
   /*----------------------- Open -------------------------------------*/
   /*------------------------------------------------------------------*/
   /* Open clob1 for READs and clob2 for WRITES */
   DBMS_LOB.OPEN(clob1, DBMS_LOB.LOB_READONLY);
   DBMS_LOB.OPEN(clob2, DBMS_LOB.LOB_READWRITE);
 
   /*------------------------------------------------------------------*/
   /*-------------------- Reading from a LOB --------------------------*/
   /*------------------------------------------------------------------*/
   DBMS_OUTPUT.PUT_LINE('storage limit : ' || dbms_lob.get_storage_limit(clob1));
   DBMS_OUTPUT.PUT_LINE('chunk size : ' || dbms_lob.getchunksize(clob1));
 
   loblen1 := DBMS_LOB.GETLENGTH(clob1);
   DBMS_OUTPUT.PUT_LINE('length : ' || loblen1);
 
   DBMS_LOB.READ(clob1, buflen, 1, buf);
   DBMS_OUTPUT.PUT_LINE('read : LOB data : ' || buf);
   DBMS_OUTPUT.PUT_LINE('New buflen : ' || buflen);
 
   DBMS_OUTPUT.PUT_LINE('substr : ' || dbms_lob.substr(clob1, 30, 1));
   DBMS_OUTPUT.PUT_LINE('instr : ' ||
                        DBMS_LOB.INSTR(clob1, 'review of the document', 1, 3));
 
   /*------------------------------------------------------------------*/
   /*-------------------- Modifying a LOB -----------------------------*/
   /*------------------------------------------------------------------*/
   DBMS_LOB.WRITE(clob2, buflen, 10, buf);
   DBMS_LOB.WRITEAPPEND(clob2, buflen, buf);
   buflen := 10;
   DBMS_LOB.ERASE(clob2, buflen, 10);
   DBMS_LOB.TRIM(clob2, 50);
 
   /* Print the LOB just modified */
   buflen := 32760;
   DBMS_LOB.READ(clob2, buflen, 1, buf);
   DBMS_OUTPUT.PUT_LINE('read : LOB data : ' || buf);
   DBMS_OUTPUT.PUT_LINE('New buflen : ' || buflen);
 
   /* Error because clob1 is open in READ mode */
   -- DBMS_LOB.WRITE(clob1, buflen, 10, buf);
 
   /*------------------------------------------------------------------*/
   /*------------- Operations involving 2 locators ---------------------*/
   /*------------------------------------------------------------------*/
 
   retval := DBMS_LOB.COMPARE(clob1, clob2, 100, 1, 1);
   if (retval < 0) then
     DBMS_OUTPUT.PUT_LINE('clob1 is smaller');
   elsif (retval = 0) then
     DBMS_OUTPUT.PUT_LINE('both clobs are equal');
   else
     DBMS_OUTPUT.PUT_LINE('clob1 is larger');
   end if;
 
   DBMS_OUTPUT.PUT_LINE('length before append: ' || DBMS_LOB.GETLENGTH(clob2));
   DBMS_LOB.APPEND(clob2, clob1);
   DBMS_OUTPUT.PUT_LINE('length after append: ' || DBMS_LOB.GETLENGTH(clob2));
 
   DBMS_OUTPUT.PUT_LINE('----------- LOB COPY operation --------');
   DBMS_LOB.COPY(clob2, clob1, loblen1, 100, 1);
   DBMS_OUTPUT.PUT_LINE('length after copy: ' || DBMS_LOB.GETLENGTH(clob2));
 
   /*------------------------------------------------------------------*/
   /*------------------- Convert CLOB to a BLOB -----------------------*/
   /*------------------------------------------------------------------*/
   DBMS_LOB.CREATETEMPORARY( blob1, false );
   dst := 1;
   src := 1;
   amt := 5;
   DBMS_LOB.CONVERTTOBLOB(blob1, clob2, amt, dst, src, DBMS_LOB.DEFAULT_CSID,
                          lang, warn);
   DBMS_OUTPUT.PUT_LINE(' Source offset returned      ' || src ) ;
   DBMS_OUTPUT.PUT_LINE(' Destination offset returned ' || dst ) ;
   DBMS_OUTPUT.PUT_LINE(' Length of CLOB      ' || dbms_lob.getlength(clob2) ) ;
   DBMS_OUTPUT.PUT_LINE(' Length of BLOB      ' || dbms_lob.getlength(blob1) ) ;
   DBMS_OUTPUT.PUT_LINE(' Warning returned    ' || warn);
   DBMS_OUTPUT.PUT_LINE(' OUTPUT BLOB contents = ' || rawtohex(blob1));
 
   /*------------------------------------------------------------------*/
   /*-------------------- Convert BLOB to a CLOB ----------------------*/
   /*------------------------------------------------------------------*/
   DBMS_LOB.CREATETEMPORARY( clob3, false );
   dst := 1;
   src := 1;
   amt := 4;
   DBMS_LOB.CONVERTTOCLOB(clob3, blob1, amt, dst, src, DBMS_LOB.DEFAULT_CSID,
                          lang, warn);
   DBMS_OUTPUT.PUT_LINE(' Source offset returned      ' || src ) ;
   DBMS_OUTPUT.PUT_LINE(' Destination offset returned ' || dst ) ;
   DBMS_OUTPUT.PUT_LINE(' Length of BLOB      ' || DBMS_LOB.GETLENGTH(blob1) ) ;
   DBMS_OUTPUT.PUT_LINE(' Length of CLOB      ' || DBMS_LOB.GETLENGTH(clob3) ) ;
   DBMS_OUTPUT.PUT_LINE(' Warning returned    ' || warn);
   DBMS_OUTPUT.PUT_LINE(' INPUT BLOB contents =  ' || rawtohex(blob1));
   DBMS_OUTPUT.PUT_LINE(' OUTPUT CLOB contents = ' || clob3);
 
   /*------------------------------------------------------------------*/
   /*----------------------- Close ------------------------------------*/
   /*------------------------------------------------------------------*/
   DBMS_OUTPUT.PUT_LINE('------------- CLOSE ---------------');
   DBMS_LOB.CLOSE(clob2);
 
   if (DBMS_LOB.ISOPEN(clob1) = 1) then
     DBMS_LOB.CLOSE(clob1);
   END if;
 
   COMMIT;
END;
/

例9-2 SecureFile固有の操作用のPL/SQL API

conn pm/pm
 
-- alter the table to make lob storage as securefile
-- assume tablespace tbs_1 is ASSM
alter table print_media move
lob(ad_composite)  store as securefile (deduplicate compress tablespace tbs_1)
lob(ad_sourcetext) store as securefile (compress tablespace tbs_1)
lob(ad_finaltext)  store as securefile (compress tablespace tbs_1)
lob(ad_photo)      store as securefile (tablespace tbs_1);
 
SET SERVEROUTPUT ON
 
DECLARE
 clob1             CLOB;
 blob1             BLOB;
 result            BINARY_INTEGER;
 
 /* --- variables for setcontenttype, getcontenttype ----*/
 get_media_type    VARCHAR2(128);
 set_media_type    VARCHAR2(128);
 
 /* --- variables for delta operations --------*/
 amount            INTEGER;
 offset            INTEGER;
 buffer            VARCHAR2(30);
 readbuf           VARCHAR2(50);
 read_amt          INTEGER;
 src_offset        INTEGER;
 dest_offset       INTEGER;
 amount_old        INTEGER;
BEGIN
 -- fetch clob, blob values
 SELECT ad_sourcetext, ad_composite
 INTO   clob1, blob1
 FROM   print_media
 WHERE  product_id = 2056 FOR UPDATE;
  
 /*------------------------------------------------------------------*/
 /*---------------------- Get Options -------------------------------*/
 /*------------------------------------------------------------------*/
 -- check whether compress option is enabled
 result := DBMS_LOB.GETOPTIONS(clob1, DBMS_LOB.OPT_COMPRESS);
 DBMS_OUTPUT.PUT_LINE('Get compress option on ad_sourcetext: '||result);
  
 -- check whether compress + deduplicate is enabled
 result := DBMS_LOB.GETOPTIONS(blob1, DBMS_LOB.OPT_DEDUPLICATE +
                                      DBMS_LOB.OPT_COMPRESS);
 DBMS_OUTPUT.PUT_LINE('Get compress + deduplicate option on ad_composite: '||result);
 
 /*------------------------------------------------------------------*/
 /*---------------------- Set Options -------------------------------*/
 /*------------------------------------------------------------------*/
 -- turn off compression 
 DBMS_LOB.SETOPTIONS(clob1, DBMS_LOB.OPT_COMPRESS, DBMS_LOB.COMPRESS_OFF);
 -- getoptions should be 0 now
 result := DBMS_LOB.GETOPTIONS(clob1, DBMS_LOB.OPT_COMPRESS);
 DBMS_OUTPUT.PUT_LINE('Compress option on clob1: '||result);
 
 -- turn off deduplication
 DBMS_LOB.SETOPTIONS(blob1, DBMS_LOB.OPT_DEDUPLICATE, DBMS_LOB.DEDUPLICATE_OFF);
 -- getoptions should be 0 now
 result := DBMS_LOB.GETOPTIONS(blob1, DBMS_LOB.OPT_DEDUPLICATE);
 DBMS_OUTPUT.PUT_LINE('Deduplicate option on blob1: '||result);
 
 /*------------------------------------------------------------------*/
 /*----------- Getcontenttype, Setcontenttype -----------------------*/
 /*------------------------------------------------------------------*/
 -- get contenttype -- should be null as content type is not set yet
 DBMS_OUTPUT.PUT_LINE(CHR(10)||'clob1 contenttype: ' || dbms_lob.getcontenttype(clob1));
 
 set_media_type := 'text/plain';
 DBMS_LOB.SETCONTENTTYPE(clob1, set_media_type);
 
 DBMS_OUTPUT.PUT_LINE('Clob1 contenttype: ' || dbms_lob.getcontenttype(clob1));
 
 -- setcontenttype for blob
 DBMS_OUTPUT.PUT_LINE('blob1 contenttype: ' || dbms_lob.getcontenttype(blob1));
 set_media_type := 'photo/jpeg';
 DBMS_LOB.SETCONTENTTYPE(blob1, set_media_type);
 
 get_media_type := DBMS_LOB.GETCONTENTTYPE(blob1);
 DBMS_OUTPUT.PUT_LINE('Blob1 contenttype: ' || get_media_type);
 
 /*------------------------------------------------------------------*/
 /*---------------------- Fragment Operations -----------------------*/
 /*------------------ Print Before Fragment Operations --------------*/
 read_amt  := 40;
 DBMS_LOB.READ(clob1, read_amt, 1, readbuf);
 DBMS_OUTPUT.PUT_LINE(CHR(10)||'Clob1 before fragment insert: '|| readbuf);
 DBMS_OUTPUT.PUT_LINE(CHR(10)||'Length of clob1 before fragment operations: '|| dbms_lob.getlength(clob1));
 
 /*--------------------- Fragment Delete ----------------------------*/
 amount := 100;
 offset := 10;
 DBMS_LOB.FRAGMENT_DELETE(clob1, amount, offset);
 
 /*--------------------- Fragment Insert ----------------------------*/
 amount    := 29;
 offset    := 1;
 buffer    := '#Verify lob Delta operations#';
 DBMS_LOB.FRAGMENT_INSERT(clob1, amount, offset, buffer);
 
 /*---------------------- Fragment Move -----------------------------*/
 amount      := 29;
 src_offset  := 100;
 dest_offset := 1;
 
 -- fragment move
 DBMS_LOB.FRAGMENT_MOVE(clob1, amount, src_offset, dest_offset);
 
 /*---------------------- Fragment Replace --------------------------*/
 amount      := 25;
 amount_old  := 29;
 offset      := 100;
 buffer      := '$Verify fragment replace$';
 
 DBMS_LOB.FRAGMENT_REPLACE(clob1, amount_old, amount, offset,buffer);
 
 COMMIT;
 
 /*------------------ Verify After Fragment Operations --------------*/
 read_amt  := 40;
 DBMS_LOB.READ(clob1, read_amt, 1, readbuf);
 DBMS_OUTPUT.PUT_LINE(CHR(10)||'Clob1 after delta insert: '|| readbuf);
 DBMS_OUTPUT.PUT_LINE(CHR(10)||'Length of clob1 after fragment operations: '|| dbms_lob.getlength(clob1));
 
EXCEPTION
 WHEN OTHERS THEN
   DBMS_OUTPUT.PUT_LINE(sqlerrm);
END;
/