Konstantin Vlasov
Konstantin Vlasov

Reputation: 41

Function in pl/sql for reading bfile into blob don't show the result

Could you tell me, why this function returns as result an empty blob value? It don't even close the BFILE type variable after the loop. I can't imaging where is the problem.

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;

I call the function this way

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

Upvotes: 3

Views: 4654

Answers (1)

Vincent Malgrat
Vincent Malgrat

Reputation: 67722

Your logic is complex, you're mixing many elements that can produce errors: namely CLOB and BFILE. You should try first to isolate which element in your function leads to this abnormal behaviour.

I suggest you run a simple function to make sure that your BLOB logic is fine:

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;

This should produce FFFFFFFF. Now you know that the problem lies with your reading of the BFILE object. We can see in your code that you have a loop withoug an exit condition. Since the program exits, we deduct that your loop exits with an error.

The documentation explains that the exception is raised by the READ procedure:

The number of bytes or characters actually read is returned in the amount parameter. If the input offset points past the End of LOB, then amount is set to 0, and a NO_DATA_FOUND exception is raised.

The exception is raised and the function exits without having return anything.

As you may know, NO_DATA_FOUND exceptions are not considered errors inside an SQL statement. The error is interpreted as NULL by the SELECT query.

You should modify your function to catch this error and exit the loop gracefully:

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;

Upvotes: 1

Related Questions