PL/SQL から BLOB への登録とバイナリデータの取り出し
PL/SQL から BLOB 型へのデータ登録と設定
- DBMS_LOB パッケージ
- UTL_RAW パッケージ
テーブルの BLOB を作成してバイナリデータを格納する
テーブルの BLOB に対して「大きな?」BLOB に値を設定しようとする場合には 一度 BLOB 項目に空のロケータを設置する必要がある。
そして、そのロケータに経由でバイナリデータの断片を繰り返し書き込んでいくというプロセスが必要になる。
以下の例のような 一片の小さなバイナリ表現であれば、暗黙変換によって直接代入可能。
INSERT INTO BLOB_MEDIA (CONTENT_ID, MEDIA)
VALUES ( 1, HEXTORAW('3E00210102CDA000C9') )
ロケータを使用して書き込む手順
- INSERT で EMPTY_BLOB を使用して空のロケータを作成して RETURNING 句でロケータを取得
- ロケータ変数を使って DBMS_LOB.WRITE 関数などでバイナリデータを繰り返し書き込む
- トランザクションをコミットする
RETURNING が使えないバージョンであれば INSERT 後に SELECT FOR UPDATE を使用して行を再取得する。ロケータを所有する行をロックしないと正しく排他制御できない。
行データの生成(INSERT)とロケータ経由の LOB 書き込み(DBMS_LOB)は独立したアクセス手段を持っている。この操作はレコードを生成しながらファイルI/O を行なっているイメージに非常に近い。
この2系統のアクセス手段があるためプログラム上では 行の INSERT をコミットした後から保持しておいたロケータ経由で LOB にデータを書き込むプログラムが記述できてしまう。しかし、このような事ができてしまうと破綻してしまうので実行時エラーとなる。
ロケータ経由でデータを書き込みたい場合にはロケータを所有する行を変更するトランザクションを発生させ、同じトランザクション内で LOB データの書き込みを実行する必要がある。
- BLOB のインサートとロケータによる書き込みとその一部を RAW に取り出すサンプル
CREATE OR REPLACE PROCEDURE RIVUS.SET_BLOB_MEDIA
IS
vBlob BLOB;
vRaw RAW(32000);
vLength BINARY_INTEGER;
vOffset BINARY_INTEGER;
BEGIN
INSERT INTO BLOB_MEDIA (CONTENT_ID, MEDIA) VALUES ( 1, EMPTY_BLOB())
RETURNING MEDIA INTO vBlob;
vRaw := UTL_RAW.CAST_TO_RAW('0123456789');
vLength := UTL_RAW.LENGTH(vRaw);
vOffset := 1;
DBMS_LOB.WRITE(vBlob, vLength, vOffset, vRaw);
vLength := 5;
DBMS_LOB.WRITEAPPEND(vBlob, vLength, vRaw);
COMMIT;
-- DBMS_LOB.WRITEAPPEND(vBlob, 5, vRaw);
-- ↑ このコメントをはずすと
-- ORA-22990: LOBロケータは複数のトランザクションにまたがることはできません。
-- エラーになる。
--
-- 取り出す分には大丈夫
DBMS_OUTPUT.PUT_LINE('BLOB のサイズ = ' || DBMS_LOB.GETLENGTH(vBlob));
vLength := 100; -- 100 バイト読み込み
vOffset := 10; -- オフセット
DBMS_LOB.READ(vBLob, vLength, vOffset, vRaw); -- vBlob ⇒ vRaw & vLength(IN/OUT)
DBMS_OUTPUT.PUT_LINE('BLOB の一部分 = ' || UTL_RAW.CAST_TO_VARCHAR2(vRaw));
DBMS_OUTPUT.PUT_LINE('└ そのサイズ = ' || vLength);
END;
/
SQL> CALL SET_BLOB_MEDIA();
BLOB のサイズ = 15
BLOB の一部分 = 901234 ← オフセットは1オリジン
└ そのサイズ = 6 ← 指定したバイト数から取り出したバイト数に書き換わる
コールが完了しました。
BLOB に関連する事項