3

この関数が結果として空の blob 値を返す理由を教えてください。ループ後に BFILE 型の変数を閉じません。どこに問題があるのか​​想像できません。

FUNCTION f$bfile_to_blob
  (I_FID_ID IN INTEGER)
  RETURN BLOB IS
   bf            BFILE;
   Amount        INTEGER := 32767;
   Position      integer := 1;
   buffer        RAW(32767);
   bl            LONG RAW := '';

   bb            BLOB;

BEGIN
  select fid_bckp into bf
   from filedoc
  where fid_id = I_FID_ID;

  dbms_lob.open(bf, dbms_lob.lob_readonly);

  DBMS_LOB.CREATETEMPORARY(bb, TRUE, DBMS_LOB.SESSION);
  LOOP
    dbms_lob.read(bf, Amount, Position, buffer);
    dbms_lob.writeappend(bb,amount,buffer);
    Position := Position + Amount;
  END LOOP;

  dbms_lob.close(bf);

  return bb;

END;

このように関数を呼び出します

select F$BFILE_TO_BLOB(fid_id) from filedoc where fid_id = 2150;
4

1 に答える 1

1

あなたのロジックは複雑です。エラーを生成する可能性のある多くの要素、つまり CLOB と BFILE が混在しています。最初に、関数内のどの要素がこの異常な動作につながるかを特定する必要があります。

BLOB ロジックが適切であることを確認するために、単純な関数を実行することをお勧めします。

create or replace FUNCTION f$bfile_to_blob
  RETURN BLOB IS
   bb            BLOB;
BEGIN
  DBMS_LOB.CREATETEMPORARY(bb, TRUE, DBMS_LOB.SESSION);
  bb := hextoraw('FFFFFFFF');
  return bb;
END;

select rawtohex(dbms_lob.substr(f$bfile_to_blob, 4000, 1)) from dual;

これにより、FFFFFFFF が生成されます。これで、BFILE オブジェクトの読み取りに問題があることがわかりました。コードで、終了条件のないループがあることがわかります。プログラムが終了するので、ループがエラーで終了すると推測します。

ドキュメントには、例外が次の手順で発生することが説明されていますREAD

実際に読み取られたバイト数または文字数は、amount パラメータで返されます。入力オフセットが LOB の末尾を超えている場合、amount は 0 に設定され、NO_DATA_FOUND例外が発生します。

例外が発生し、関数は何も返さずに終了します。

ご存知かもしれませんが、NO_DATA_FOUND例外は SQL ステートメント内のエラーとは見なされません。NULLエラーはクエリによって解釈されSELECTます。

このエラーをキャッチしてループを正常に終了するように関数を変更する必要があります。

FUNCTION f$bfile_to_blob(I_FID_ID IN INTEGER)
   RETURN BLOB IS
   bf       BFILE;
   Amount   INTEGER := 32767;
   Position INTEGER := 1;
   buffer   RAW(32767);
   bl       LONG RAW := '';
   bb       BLOB;
BEGIN
   SELECT fid_bckp
     INTO bf
     FROM filedoc
    WHERE fid_id = I_FID_ID;
   dbms_lob.open(bf, dbms_lob.lob_readonly);
   DBMS_LOB.CREATETEMPORARY(bb, TRUE, DBMS_LOB.SESSION);

   LOOP
      BEGIN
         dbms_lob.read(bf, Amount, Position, buffer);
      EXCEPTION 
         WHEN NO_DATA_FOUND THEN
            EXIT;
      END;
      dbms_lob.writeappend(bb, amount, buffer);
      Position := Position + Amount; 
   END LOOP;

   dbms_lob.close(bf);

   RETURN bb;
END;
于 2012-09-04T13:05:36.377 に答える