Mac De Oracle (PL/SQL De UNCOMPRESS) Tweet
Oracle10g R1から UTL_COMPRESSパッケージという、PL/SQLでデータの圧縮/解凍を行う為のパッケージが提供されているのをご存知だろうか?
恐らく、大きなデータを圧縮してBLOBとしてデータベースに格納し、取り出す時に解凍するというのが一般的な利用方法なのではないかと思うのだが、Mac De Oracle としては、そのまま試すのでは面白くない!
ということで、UTL_FILEパッケージを利用し、ディレクトリオブジェクトにある圧縮ファイルを解凍したり、テキストファイルを圧縮してみることにする。さて、うまくいきますかどうか。。。
尚、BLOBをディレクトリオブジェクト以下に書き出す方法は、PL/SQL De Phython Challengeでも利用した方法である。以前はコードを掲載していなかったが、今回は、それに近いコードも載せることにする。
(UTL_FILEパッケージでディレクトリオブジェクト以下にあるファイルを読み書きするには、Oracle9i R2以降が必要である。)
マニュアルにも書いてあるが、UTL_COMPRESSの圧縮、解凍は、gzip/gunzipと互換があるということなので素直に信じて試してみる!
まずは gzip するテキストファイルの準備から。
以下のようなテキストファイルを用意する。テキストファイルの内容は、「Oracle10g R1 PL/SQL タイプ及びパッケージリファレンス」のUTL_COMPRESSパッケージの解説を一部を引用することにした。(テキストファイルの文字コードは、SJIS、データベースキャラクタセットは、JA16SJISTILDEである。)
操作上の注意
■ LZ* ファンクションによって戻された一時 LOB は、コール元が
DBMS_ LOB.FREETEMPORARY コールを使用して解放する必要があります。
■ LZ_COMPRESS* または LZ_UNCOMPRESS* に渡された BFILE は、
DBMS_LOB.FILEOPENでオープンする必要があります。
■ 特別な状況(入力がすでに圧縮されている場合)では、UTL_COMPRESS サブプログラムの
1 つで生成された出力が、入力と同じ大きさかまたは入力よりもわずかに大きくなる
ことがあります。
■ UTL_COMPRESS で圧縮したデータの出力は、1 つのファイル上の gzip(-n オプション を指定)/gunzip と
互換性があります。
Last login: Mon Aug 19 16:42:12 on ttyp1
Welcome to Darwin!
G5Server:˜ oracle$ gzip -cvn org.txt > org.gz
org.txt: 30.2%
G5Server:˜ oracle$ gzip -l org.gz
compressed uncompressed ratio uncompressed_name
408 559 30.2% org
G5Server:˜ oracle$ ls -l
total 48096
中略
-rw-r--r-- 1 oracle oinstall 408 Aug 20 06:35 org.gz
-rw-r--r-- 1 oracle oinstall 559 Aug 20 06:35 org.txt
中略
G5Server:˜ oracle$
準備は整ったので早速取りかかる。今回も Oracle SQL Developer 1.0 for MacOSXを利用する。
だ〜〜〜〜っと、コード書をきなぐり、即、実行!(無名PL/SQLブロックにしてあるが、ストアドプロシージャでもファンクションでも、パッケージで実装しても全く問題はない。尚、事前にディレクトリオブジェクトは作成してあり、無名PL/SQLブロックを実行するユーザへ読み込み権限と書き込み権限を付与してある。)
圧縮前のテキストファイル(org.txt)と、org.gzをUTL_COMPRESS.LZ_UNCOMPRESS()で解凍したファイル(uncompressed_file.txt)が同じ内容であることを確認する。(diffを取って見せるのがいいのだが、それだけだとMacOSXの奇麗なGUIが見れないので、ファイルを開いて確認する。)
以下に今回作成したコードを示す。
DECLARE
v_src_gzipped_file BFILE;
v_uncompressed_blob BLOB;
v_directory_name VARCHAR2(30);
v_src_gzipped_file_name VARCHAR2(510);
v_dest_file_name VARCHAR2(510);
PROCEDURE close_bfile
(
i_bfile IN OUT NOCOPY BFILE
)
IS
BEGIN
IF DBMS_LOB.ISOPEN(i_bfile) = 1 THEN
DBMS_LOB.CLOSE(i_bfile);
END IF;
END close_bfile;
PROCEDURE write_blob_to_file
(
i_directory_name IN VARCHAR2,
i_file_name IN VARCHAR2,
i_src_blob IN OUT NOCOPY BLOB
)
IS
v_file UTL_FILE.FILE_TYPE;
BEGIN
v_file := UTL_FILE.FOPEN(
UPPER(i_directory_name),
i_file_name,
'wb',
32767
);
-- ファイルへ書き出すBLOBはオープンされていることを前提とする
DECLARE
c_chunk_size CONSTANT PLS_INTEGER := 32767;
v_buffer RAW(32767);
v_amount PLS_INTEGER := c_chunk_size;
v_num_of_chunk PLS_INTEGER;
BEGIN
v_num_of_chunk := CEIL(DBMS_LOB.GETLENGTH(i_src_blob)/c_chunk_size);
FOR chunk# IN 1..v_num_of_chunk LOOP
DBMS_LOB.READ(
i_src_blob,
v_amount,
(c_chunk_size * (chunk# - 1)) + 1, /*offet*/
v_buffer
);
UTL_FILE.PUT_RAW(v_file, v_buffer, TRUE);
END LOOP;
END;
UTL_FILE.FCLOSE(v_file);
END write_blob_to_file;
--
BEGIN
-- ディレクトリ名の設定
v_directory_name := 'MYDIR';
-- 圧縮ファイル名
v_src_gzipped_file_name := 'org.gz';
-- 解凍ファイル名
v_dest_file_name := 'uncompressed_file.txt';
DBMS_OUTPUT.PUT_LINE('========== uncompress start ==========');
-- 圧縮ファイルをBFILEとして取り込む
v_src_gzipped_file
:= BFILENAME(UPPER(v_directory_name), v_src_gzipped_file_name);
DBMS_LOB.OPEN(v_src_gzipped_file);
-- BFILEを解凍し一時BLOBへ
v_uncompressed_blob := UTL_COMPRESS.LZ_UNCOMPRESS(v_src_gzipped_file);
-- BLOBを書き出す
write_blob_to_file(
UPPER(v_directory_name),
v_dest_file_name,
v_uncompressed_blob
);
-- 一時LOBの解放及び、BFILEのクローズ
DBMS_LOB.FREETEMPORARY(v_uncompressed_blob);
close_bfile(v_src_gzipped_file);
DBMS_OUTPUT.PUT_LINE('========== uncompress end ==========');
EXCEPTION
WHEN OTHERS THEN
-- 一時LOBの解放及び、BFILEのクローズ
DBMS_LOB.FREETEMPORARY(v_uncompressed_blob);
close_bfile(v_src_gzipped_file);
RAISE;
END;
/
さて、次回は、テキストファイルを読み込み圧縮してみることにする。
| 固定リンク | 0
コメント