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 语句中的错误。该错误被查询解释NULLSELECT

您应该修改您的函数以捕获此错误并优雅地退出循环:

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 回答